Python - updating a set - python-3.x

I'm trying to update a set of nodes with their positions (coordinates) using Python.
n = 5 #number of current nodes
vertices = []
vertices=list(range(n)) # list of vertices=[0,1,2,3,4]
I'm creating a random set of points as follows for each element in vertices:
pos = {i:(random.randint(0,50),random.randint(0,50)) for i in vertices}
Also, I have another list(called "s") with some coordinates and I'm enumerating those elements in "s" to add an index(to continue with indices in "vertices") to each coordinate in "s".
for index, i in enumerate(s , vertices[-1]+1):
print(index, i)
Then, I'm getting my output as
5 (29.5, 34.0)
6 (20.0, 25.75)
7 (23.75, 36.0)
Now I need to update my set "pos" with these points and their corresponding indices. How can I do that?

You can assign like this while iterating itself instead of just printing
for index, i in enumerate(s, vertices[-1] + 1):
pos[index] = i
And finally, the pos will be something like
{0: (0, 10), 1: (16, 33), 2: (17, 36), 3: (40, 13), 4: (26, 39), 5: (29.5, 34.0), 6: (20.0, 25.75), 7: (23.75, 36.0)}

Related

How to remove minimum weight edge from each node in a networkx graph

I have an undirected graph and I'm looking for a way to remove the minimum weight edge from every node. I tried several methods but they all seem to fail.
Given a complete graph
>>> G = nx.complete_graph(n=5)
>>> for (u, v) in G.edges():
... G.edges[u,v]['weight'] = random.randint(0,10)
To take the minimum weight edge incident to a node and then remove it you can do as follows.
>>> for u in G.nodes():
... min_weight_edge = min(G.edges(u), key=lambda x: G.get_edge_data(x[0], x[1])["weight"])
... G.remove_edge(*min_weight_edge)
...
First create a complete graph with random weights:
g = nx.complete_graph(5)
for (u,v,w) in g.edges(data=True):
w['weight'] = random.randint(0,10)
Option1: iterate over the nodes and remove the minimum weight edge.
for n in g.nodes():
min_weight = (-1,-1,float("inf"))
for e in g.edges(nbunch=n,data="weight"):
#print(e)
if min_weight[2] > e[2]:
min_weight = e
print(min_weight)
g.remove_edge(min_weight[0], min_weight[1])
Option 2: remove edges in the end.
Only remove the edges in the end, checking if the edge is already in the list of edges to be removed.
edges_to_remove = set()
for n in g.nodes():
min_weight = (-1,-1,float("inf"))
for e in g.edges(nbunch=n,data="weight"):
#print(e)
if min_weight[2] > e[2]:
min_weight = e
if (min_weight[1],min_weight[0]) not in edges_to_remove:
print(min_weight)
edges_to_remove.add((min_weight[0],min_weight[1]))
for e in edges_to_remove:
g.remove_edge(*e)
Notice that these two solutions yield different results:
For the same graph:
Edges (u,v,weight) removed using Option 1:
(0, 3, 3)
(1, 2, 0)
(2, 3, 7)
(3, 1, 8)
(4, 1, 3)
Edges (u,v,weight) removed using Option 2:
(0, 3, 3)
(1, 2, 0)
(4, 1, 3)
The first option removes the smallest weight edge for each node depending on the order!, i.e if the smallest weight edge has already been removed it will remove the next smallest weight edge. Will always remove as many edges as the number of nodes.
The second option only removes the smallest weight edge for each node, i.e if the smallest edge of a given node has already been removed it will not remove any edge.

How to find highest number from the vector provided?

Say, a dictionary is provided with certain values.
How to find the highest number ?
Input
d1 = {1: 1, 2: 6, 3: 7, 4: 1, 5: 3}
vector = 5
d1 = {1: 1, 2: 6, 3: 7, 4: 1, 5: 3}
vector = 5
l1 = list(td.values())
Based on vector value, it should print output.
vector is 5, so sum of the dict-values to form vector is 3,1,1
Corresponding keys are 5,4,1
so, the output should be 541 but slight change here.
Since value '1' is associated with multiple keys, it should pick up highest key,
so, output should be 544 instead of 541 (For above input, to brief about combinations without considering '1+1+1+1+1' to '44444')
Another example
d1 = {1: 1, 2: 6, 3: 7, 4: 1, 5: 3}
vector = 7
Possible combinations:
3 # --> Key of 7
21 # --> Key of 6 & 1 (6+1 = 7)
24 # --> Key of 6 & 1 (6+1 = 7)
12 # --> Key of 1 & 6 (1+6 = 7)
42 # --> Key of 1 & 6 (1+6 = 7)
Output : 42 (Highest number)
Another
d1 = {1:9,2:4,3:2,4:2,5:6,6:3,7:2,8:2,9:1}
vector = 5
here, it would be 1+2+2 (988).
But, '1' can also be added 5 times to form vector 5,
which would be '99999'
Since #Patrick Artner requested for minimal reproducible example, posting this though doesn't work as expected.
from itertools import combinations
def find_sum_with_index(l1, vector):
index_vals = [iv for iv in enumerate(l1) if iv[1] < target]
for r in range(1, len(index_vals) + 1):
for perm in combinations(index_vals, r):
if sum([p[1] for p in perm]) == target:
yield perm
d1 = {1: 1, 2: 6, 3: 7, 4: 1, 5: 3}
vector=5
l1=list(d1.values())
for match in find_sum_with_index(l1, vector):
print(dict(match))
Is there any specific algorithm to be chosen for these kind of stuffs ?
Similar to the other answer but allowing repeatedly using the same keys to get the max number of keys which values sum up to vector:
d1 = {1: 1, 2: 6, 3: 7, 4: 1, 5: 3}
vector = 7
#create a dict that contains value -> max-key for that value
d2 = {}
for k,v in d1.items():
d2[v] = max(d2.get(v,-1), k)
def mod_powerset(iterable,l):
# uses combinations_with_replacement to allow multiple usages of one value
from itertools import chain, combinations_with_replacement
s = list(set(iterable))
return chain.from_iterable(combinations_with_replacement(s, r) for r in range(l))
# create all combinations that sum to vector
p = [ s for s in mod_powerset(d1.values(),vector//min(d1.values())+1) if sum(s) == vector]
print(p)
# sort combinations by length then value descending and take the max one
mp = max( (sorted(y, reverse=True) for y in p), key=lambda x: (len(x),x))
# get the correct keys to be used from d2 dict
rv = [d2[num] for num in mp]
# sort by values, biggest first
rv.sort(reverse=True)
# solution
print(''.join(map(str,rv)))
Original powerset - see itertools-recipes.
There are some steps involved, see documentation in comments in code:
d1 = {1: 1, 2: 6, 3: 7, 4: 1, 5: 3}
vector = 7
# create a dict that contains value -> sorted key-list, used to get final keys
from collections import defaultdict
d2 = defaultdict(list)
for k,v in d1.items():
d2[v].append(k)
for k,v in d2.items():
d2[k] = sorted(v, reverse=True)
from itertools import chain, combinations
def powerset(iterable):
"see itertools: powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
s = list(iterable)
return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
# create all combinations that sum to vector
p = [ s for s in powerset(d1.values()) if sum(s) == vector]
# sort combinations by length then value descending and take the max one
mp = max( (sorted(y, reverse=True) for y in p), key=lambda x: (len(x),x))
# get the correct keys to be used from d2 dict
rv = []
for num in mp:
rv.append(d2[num][0])
# remove used key from list
d2[num][:] = d2[num][1:]
# sort by values, biggest first
rv.sort(reverse=True)
# solution
print(''.join(map(str,rv)))
For powerset - see itertools-recipes.

Python for loop with ifs

What I have:
I have two keys in a dictionary:
one with values and
one with the index of the value.
d = {}
d['inds'] = [0, 5, 4, 2, 2, 5, 1]
d['vals'] = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]
What I want to do:
I want to loop through the dictionary and:
If the next iteration index = the last iteration index +1, to list the corresponding value
If the next iteration index does not = the last iteration index +1, print 0 and keep going. so basically just filling in 0 when there is a missing index
What I have tried
If I use the below loop:
for i in d['inds']:
for v in d['vals']:
for x in range(0, i):
if i == x+1:
print(v)
break
else:
print(0)
I get the list of values 6 times.
So I tried swapping i and x:
for i in d['inds']:
for v in d['vals']:
for x in range(0, i):
if x == i+1:
print(v)
break
else:
print(0)
Now I just get 0 listed 7 times.
TL;DR
How do I loop through a dictionary's values and indexes with a conditional statement, what am I doing wrong?
If I understand correctly, you want something like this:
for i in range(len(d['inds'])):
if i in d['inds']:
print(d['vals'][i])
else:
print(0)
This iterates through all the possible indices, prints 0 if the current index is not in d['inds'], and prints the value at the current index if it is.
This solution requires functions chain and defaultdict:
from itertools import chain
from collections import defaultdict
Create a new dictionary of lists:
G = defaultdict(list)
Populate it with the data from d:
for k,v in zip(d['inds'], d['vals']):
G[k].append(v)
#{0: [1.0], 5: [2.0, 6.0], 4: [3.0], 2: [4.0, 5.0], 1: [7.0]}
Create a range of indexes:
indexes = range(min(d['inds']), max(d['inds']) + 1)
Lookup each index in the new dictionary. If an index is not in the dictionary, use [0] as the value. The result is a nested list that can be flattened with chain:
list(chain.from_iterable(G.get(x, [0]) for x in indexes))
#[1.0, 7.0, 4.0, 5.0, 0, 3.0, 2.0, 6.0]

3Sum using python3 and enumarate

I want to solve the following task using 'enumerate' in python3
The way enumerate works is demonstrated below
nums=(2,7,1,15) # a tuple
for num in enumerate(nums):
print(num, 'hello')
#output
#(0, 2) hello #enumarate(nums) = (0,2)
#(1, 7) hello
#(2, 1) hello
#(3, 15) hello
for count, num in enumerate(nums):
print(num, 'hello')
# Output
#2 hello here count=0 but not displayed
#7 hello here count=1 but not displayed
#1 hello here count=2 but not displayed
#15 hello here count=3 but not displayed
Using the above principle, given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = target sum? Find all unique triplets in the array which gives the sum = target sum.
A solution set for target sum =10 is:
[
[0,1,2]
]
where num at 0th index+num at 1st index+num at 2nd index(7+2+1=10).
Do you have an idea for an algorithm to solve the problem?
I would probably do something like build up two dicts listing all the ways to use the array indexes make a sum with 1 number and 2 numbers to be a certain key value.
E.g., if I had been given nums = [2, 7, 1, 2, 3], I would write code to build up a table like:
one_sum = {1: [2],
2: [0, 3],
3: [4],
7: [1]}
I would use a defaultdict from collections module to efficiently write this code (initialized as one_sum = defaultdict(list) above, though a set would also be a valid data structure for the problem).
It would be straightforward to use enumerate for this part; e.g.,
for i, n in enumerate(nums):
one_sum[n].append(i)
Then I would then build up a two_sum table this time showing all pairs of indexes that make a certain sum. Continuing with the example above, I would want to generate:
two_sum = {3: [(0, 2), (2, 3)],
4: [(2, 4)],
5: [(0, 4), (3, 4)],
8: [(1, 2)],
9: [(0, 1), (1, 3)],
10: [(1, 4)]}
(Note one way to efficiently do this is to loop through the built up one_sum, but be careful not to re-use an index e.g., don't add (2,2) or (4,4) to two_sum[4] because while nums[2] + nums[2] does add up to 4, it uses an index twice (so isn't unique). Also be careful not to double add indexes that are out of order.)
Finally I would loop through the one_sum dict, looking at indices that sum to k and then look in two_sum to see if there are any pairs of indices that sum to target-k, and if so then join the pairs together (checking to sort indices and not repeat indices in a tuple) having found a solution.
For a target of 10 this would ideally build up
three_sum = [(0,1,2), (1,2,3)]
# Note both were added from combining one_sum[1] with two_sum[9]
# nothing from combining one_sum[2] with two_sum[8] as they reuse indexes
# nothing from combining one_sum[3] as two_sum[7]==[]
# nothing new from combining one_sum[7] with two_sum[3] as (0,1,2) and (1,2,3) already present.
Here's a brute force method. It's not as efficient as this algorithm can be, mind you.
def f(nums, target):
sols = []
for i1, n1 in enumerate(nums):
for i2, n2 in enumerate(nums[i1+1:]):
for i3, n3 in enumerate(nums[i2+1:]):
if (n1 + n2 + n3 == target):
sols.append([i1, i2, i3])
return sols

Networkx bug? color is misplaced

I people, I'm trying to plot a network graph using networkx module, but I am having results I was not expecting and I am starting to ask myself if it is any module issue!
I have this code inside a class:
def plotGraph(self):
conn = []
nodeLabel = {}
for node_idx in self.operatorNodes:
print("i = ", node_idx)
print(self.node[node_idx].childs)
for child in self.node[node_idx].childs:
conn.append((child.idx, node_idx))
for i in range(self.nn):
nodeLabel[i] = str(i) + ": " + self.node[i].opString
node_color = ['blue'] * self.nn
#for i in range(self.nOutputs):
# node_color[i] = 'red'
node_color[0] = 'red'
print('Graph Conn = ', conn)
print('Graph Color = ', node_color)
# you may name your edge labels
labels = map(chr, range(65, 65 + len(conn)))
print('nodeLabel = ', nodeLabel)
draw_graph(conn, nodeLabel, node_color=node_color, labels=labels)
From the prints I can see that what is being passed inside the draw_graph is (draw_graph code is based in https://www.udacity.com/wiki/creating-network-graphs-with-python):
Graph Conn = [(2, 0), (3, 0), (4, 1), (5, 1), (6, 2), (7, 2), (8, 5), (9, 5)]
Graph Color = ['red', 'blue', 'blue', 'blue', 'blue', 'blue', 'blue', 'blue', 'blue', 'blue']
nodeLabel = {0: '0: mul', 1: '1: mul', 2: '2: mul', 3: '3: cte', 4: '4: cte', 5: '5: sum', 6: '6: cte', 7: '7: cte', 8: '8: cte', 9: '9: cte'}
Yet the plot is the following
draw_graph code is:
def draw_graph(graph, nodeLabel, node_color, labels=None, graph_layout='shell',
node_size=1600, node_alpha=0.3,
node_text_size=12,
edge_color='blue', edge_alpha=0.3, edge_tickness=1,
edge_text_pos=0.3,
text_font='sans-serif'):
# create networkx graph
G=nx.DiGraph()
# add edges
for edge in graph:
G.add_edge(edge[0], edge[1])
# these are different layouts for the network you may try
# shell seems to work best
if graph_layout == 'spring':
graph_pos = nx.spring_layout(G)
elif graph_layout == 'spectral':
graph_pos = nx.spectral_layout(G)
elif graph_layout == 'random':
graph_pos = nx.random_layout(G)
else:
graph_pos = nx.shell_layout(G)
# draw graph
nx.draw_networkx_edges(G, graph_pos, width=edge_tickness, alpha=edge_alpha, edge_color=edge_color)
nx.draw_networkx_labels(G, graph_pos, labels=nodeLabel, font_size=node_text_size, font_family=text_font)
if labels is None:
labels = range(len(graph))
edge_labels = dict(zip(graph, labels))
nx.draw_networkx_edge_labels(G, graph_pos, edge_labels=edge_labels, label_pos=edge_text_pos)
nx.draw(G, graph_pos, node_size=node_size, alpha=node_alpha, node_color=node_color)
Has can be seen, the Graph Color in 0 position is red and the remain should be blue, yet the plot is putting in the third node! There is no way for me to access node 1 has well, apparently, nodes are misplaced! The nodes color are placed in the following positions [2, 0, 3, 4, 5,....].
When you use nx.draw and pass it an (optional) list of colors, it will assign those colors to the nodes in the same order as the (optional) nodelist. But you didn't define nodelist. So it will default to whatever order comes out of G.nodes().
Since the underlying data structure for a networkx graph is a dictionary, you have to deal with the fact that you cannot count on the nodes to have any specified order.
Try passing nodelist into the nx.draw command in the order you want.

Resources