I want to create a dictionary using this list of pairs:
pairs = [('a', 'c'), ('b', 'c'), ('b', 'e'), ('c', 'a'), ('c', 'b'), ('c', 'd'), ('c', 'e'), ('d', 'c'), ('e', 'c'), ('e', 'f')]
I want to return something like this:
{ "a" : ["c"],
"b" : ["c", "e"],
"c" : ["a", "b", "d", "e"],
"d" : ["c"],
"e" : ["c", "f"],
"f" : []}
So, basically, every element in the pair has to be represented as a key even if they have an empty list. I have tried using this code below:
graph = {}
for k, v in pairs:
if k not in d:
d[k] = []
d[k].append(v)
but it returns only the first element in the pair as key:
{'a': ['c'],
'b': ['c', 'e'],
'c': ['a', 'b', 'd', 'e'],
'd': ['c'],
'e': ['c', 'f']}
pairs = [('a', 'c'), ('b', 'c'), ('b', 'e'), ('c', 'a'), ('c', 'b'), ('c', 'd'), ('c', 'e'), ('d', 'c'), ('e', 'c'), ('e', 'f')]
d = {}
for k, v in pairs:
d.setdefault(v, [])
d.setdefault(k, []).append(v)
from pprint import pprint
pprint(d)
Prints:
{'a': ['c'],
'b': ['c', 'e'],
'c': ['a', 'b', 'd', 'e'],
'd': ['c'],
'e': ['c', 'f'],
'f': []}
Adaptations needed to your existing code, which is:
graph = {}
for k, v in pairs:
if k not in d:
d[k] = []
d[k].append(v)
You are calling the output dictionary graph when you initialise it but then d inside the loop. Probably you corrected this already (as otherwise you would be getting an error), but it should obviously be the same (say d) in both cases.
If you want all the values to exist as keys in the dictionary (with empty lists if they do not exist as keys in the input dictionary), then simply add inside the loop the same thing as you are already doing with k, but with v instead:
if v not in d:
d[v] = []
Related
How to shuffle list items keeping the similar items unshuffled? E.g. for the list 'L', I want to shuffle among the unique items.
L=[a,a,b,b,c,c,d,d]
For the above list, I want to get
shuffled_L=[c,c,a,a,d,d,b,b]
Group into tuples, shuffle the tuples, flatten the list again:
>>> from itertools import groupby, chain
>>> from random import shuffle
>>> L = ["a", "a", "b", "b", "c", "c", "d", "d"]
>>> L_ = [tuple(v) for _, v in groupby(L)]
[('a', 'a'), ('b', 'b'), ('c', 'c'), ('d', 'd')]
>>> random.shuffle(L_)
[('b', 'b'), ('a', 'a'), ('d', 'd'), ('c', 'c')]
>>> list(chain.from_iterable(L_))
['b', 'b', 'a', 'a', 'd', 'd', 'c', 'c']
This assumes the original L is already sorted. If it isn't, sort it before the groupby step.
applying #suddents_appearence method from the comments
>>> import random
>>> import itertools
>>> from collections import Counter
>>> L=["a","a","b","b","c","c","d","d"]
>>> count=Counter(L)
>>> sample=random.sample(sorted(count),len(count))
>>> _shuffled_L=list(map(lambda x:[x]*count.get(x),sample))
>>> shuffled_L=list(itertools.chain.from_iterable(_shuffled_L))
>>> shuffled_L
['d', 'd', 'b', 'b', 'a', 'a', 'c', 'c']
I need to create every combination for list1, but add list2 to every combination of list1.
For example, this creates a combination for every value for list1:
list1 = ["a", "b" , "c"]
list2 = ["d", "e"]
list(itertools.combinations(list1, 2))
[('a', 'b'), ('a', 'c'), ('b', 'c')]
But I would like the result to be:
[('a', 'b', 'd', 'e'), ('a', 'c'', d', 'e'), ('b', 'c', 'd', 'e')]
I have tried these common approaches, but am getting undesired results:
list1 = ["a", "b" , "c"]
list2 = ["d", "e"]
print(list(itertools.combinations(list1, 2)).extend(list2))
None
print(list(itertools.combinations(list1, 2)) + list2)
[('a', 'b'), ('a', 'c'), ('b', 'c'), 'd', 'e']
print(list(itertools.combinations(list1, 2) + list2))
TypeError: unsupported operand type(s) for +: 'itertools.combinations' and 'list'
Any help would be appreciated. Thanks.
You can first generate a tuple of size 2 combinations for each list separately, then compute the cartesian product of those to combination lists:
import itertools
list1 = ["a", "b" , "c"]
list2 = ["d", "e"]
iter1 = itertools.combinations(list1, 2)
iter2 = itertools.combinations(list2, 2)
# If you want to add a subset of size 2 from list 2:
product = itertools.product(iter1, iter2)
answer = list(map(lambda x: (*x[0], *x[1]), product))
# [('a', 'b', 'd', 'e'), ('a', 'c', 'd', 'e'), ('b', 'c', 'd', 'e')]
However, if you want to add all elements of list2 you can use:
import itertools
list1 = ["a", "b" , "c"]
list2 = ["d", "e", "f"]
iter1 = itertools.combinations(list1, 2)
# If you want to add all elements of list2
product = itertools.product(iter1, [list2])
answer = list(map(lambda x: (*x[0], *x[1]), product))
# [('a', 'b', 'd', 'e', 'f'), ('a', 'c', 'd', 'e', 'f'), ('b', 'c', 'd', 'e', 'f')]
I'm doing coursework which involves graphs. I have edge lists E=[('a','b'),('a','c'),('a','d'), ('b','c') etc. ] and I want to a function to convert them into adjacency matrices in the form of dictionaries {'a':['b','c','d'], 'b':['a', etc. } so that I can use a function that only inputs these dictionaries.
My main issue is I can't figure out how to use a loop to add key:values without just overwriting the lists. A previous version of my function would output [] as all values because 'f' has no connections.
I've tried this:
V = ['a','b','c','d','e','f']
E=[('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]
def EdgeListtoAdjMat(V,E):
GA={}
conneclist=[]
for v in V:
for i in range(len(V)):
conneclist.append([])
if (v,V[i]) in E:
conneclist[i].append(V[i])
for i in range(len(V)):
GA[V[i]]=conneclist[i]
return(GA)
EdgeListtoAdjMat(V,E) outputs:
{'a': [], 'b': ['b'], 'c': ['c', 'c'], 'd': ['d', 'd', 'd'], 'e': [], 'f': []}
whereas it should output:
{'a':['b','c','d'],
'b':['a','c','d'],
'c':['a','b','d'],
'd':['a','b','c'],
'e':[],
'f':[]
}
The logic of what you're trying to achieve is actually quite simple:
V = ['a','b','c','d','e','f']
E=[('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]
result = {}
for elem in V:
tempList = []
for item in E:
if elem in item:
if elem == item[0]:
tempList.append(item[1])
else:
tempList.append(item[0])
result[elem] = tempList
tempList = []
print(result)
Result:
{'a': ['b', 'c', 'd'], 'b': ['a', 'c', 'd'], 'c': ['a', 'b', 'd'], 'd': ['a', 'b', 'c'], 'e': [], 'f': []}
For every element in V, perform a check to see whether that element exists in any tuple in E. If it exists, then take the element that together form a pair on that tuple and append to a temporary list. After checking every element in E, update the result dictionary and move to the next element of V until you're done.
To get back to your code, you need to modify it as following:
def EdgeListtoAdjMat(V,E):
GA={}
conneclist=[]
for i in range(len(V)):
for j in range(len(V)):
# Checking if a pair of two different elements exists in either format inside E.
if not i==j and ((V[i],V[j]) in E or (V[j],V[i]) in E):
conneclist.append(V[j])
GA[V[i]]=conneclist
conneclist = []
return(GA)
A more efficient approach is to iterate through the edges and append to the output dict of lists the vertices in both directions. Use dict.setdefault to initialize each new key with a list. And when the iterations over the edges finish, iterate over the rest of the vertices that are not yet in the output dict to assign to them empty lists:
def EdgeListtoAdjMat(V,E):
GA = {}
for a, b in E:
GA.setdefault(a, []).append(b)
GA.setdefault(b, []).append(a)
for v in V:
if v not in GA:
GA[v] = []
return GA
so that given:
V = ['a', 'b', 'c', 'd', 'e', 'f']
E = [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]
EdgeListtoAdjMat(V, E)) would return:
{'a': ['b', 'c', 'd'], 'b': ['a', 'c', 'd'], 'c': ['a', 'b', 'd'], 'd': ['a', 'b', 'c'], 'e': [], 'f': []}
Since you already have your list of vertices in V, it is easy to prepare a dictionary with an empty list of connections. Then, simply go through the edge list and add to the array on each side:
V = ['a','b','c','d','e','f']
E = [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]
GA = {v:[] for v in V}
for v1,v2 in E:
GA[v1].append(v2)
GA[v2].append(v1)
I think your code is not very pythonic, you could write a more readable code that is simpler to debug and also faster since you are using python's built-in libraries and numpy's indexing.
def EdgeListToAdjMat(V, E):
AdjMat = np.zeros((len(V), len(V))) # the shape of Adjancy Matrix
connectlist = {
# Mapping each character to its index
x: idx for idx, x in enumerate(V)
}
for e in E:
v1, v2 = e
idx_1, idx_2 = connectlist[v1], connectlist[v2]
AdjMat[idx_1, idx_2] = 1
AdjMat[idx_2, idx_1] = 1
return AdjMat
If you'd consider using a library, networkx is designed for these type of network problems:
import networkx as nx
V = ['a','b','c','d','e','f']
E = [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]
G=nx.Graph(E)
G.add_nodes_from(V)
GA = nx.to_dict_of_lists(G)
print(GA)
# {'a': ['c', 'b', 'd'], 'c': ['a', 'b', 'd'], 'b': ['a', 'c', 'd'], 'e': [], 'd': ['a', 'c', 'b'], 'f': []}
You can convert the edge list to the map using itertools.groupby
from itertools import groupby
from operator import itemgetter
V = ['a','b','c','d','e','f']
E = [('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]
# add edge in the other direction. E.g., for a -> b, add b -> a
nondirected_edges = E + [tuple(reversed(pair)) for pair in E]
# extract start and end vertices from an edge
v_start = itemgetter(0)
v_end = itemgetter(1)
# group edges by their starting vertex
groups = groupby(sorted(nondirected_edges), key=v_start)
# make a map from each vertex -> adjacent vertices
mapping = {vertex: list(map(v_end, edges)) for vertex, edges in groups}
# if you don't need all the vertices to be present
# and just want to be able to lookup the connected
# list of vertices to a given vertex at some point
# you can use a defaultdict:
from collections import defaultdict
adj_matrix = defaultdict(list, mapping)
# if you need all vertices present immediately:
adj_matrix = dict(mapping)
adj_matrix.update({vertex: [] for vertex in V if vertex not in mapping})
I'm trying to get groups of permutations/combinations (r=2) that each member appear only once
I used python 'combinations' package to have the combinations.
For example: the members are: a,b,c,d.
The combinations are: [a,b],[a,c],[a,d],[b,c],[b,d]...
My desired output is:
[ {[a,b],[c,d]},{[a,c],[b,d]},{[a,d],[b,c]}...]
I would like to know what is the terminology for that case and if there is already implementation for that.
Thanks.
Here's a way to do it:
from itertools import combinations, chain
l = ['a','b','c','d']
c = list(combinations(l,2))
[set(i) for i in list(combinations(c,2)) if (len(set(l) & set(chain(*i))) == len(l))]
[{('a', 'b'), ('c', 'd')}, {('a', 'c'), ('b', 'd')}, {('a', 'd'), ('b', 'c')}]
Explanation
You can use itertools.combinations twice, in order to get all the 2 tuple combinations from:
list(combinations(l,2))
[('a', 'b'), ('a', 'c'), ('a', 'd'), ('b', 'c'), ('b', 'd'), ('c', 'd')]
And select only those whose set of elements intersect with that of the original list, len(set(l) & set(chain(*i))) == len(l)) for every possible combination.
You can find the permutations up to r and then filter the results:
def combinations(d, d1, r, _c = [], _start=[]):
if len([i for b in _c for i in b]) == len(d1):
yield _c
else:
for i in d:
if i not in _start:
if len(_start+[i]) < r:
yield from combinations(d, d1, r, _c, _start=_start+[i])
else:
_d = sorted(_start+[i])
yield from combinations([i for i in d if i not in _d], d1,r, _c+[_d], [])
data = ['a', 'b', 'c', 'd']
_r = list(combinations(data, data, 2))
new_d = [a for i, a in enumerate(_r) if a not in _r[:i]]
Output:
[[['a', 'b'], ['c', 'd']], [['a', 'c'], ['b', 'd']], [['a', 'd'], ['b', 'c']], [['b', 'c'], ['a', 'd']], [['b', 'd'], ['a', 'c']], [['c', 'd'], ['a', 'b']]]
I have two Lists in my program list1 and list2 which looks like the following:
list1 = ['ABC',
'ABD',
'ABE',
'ABF',
'ABG',
'ABH',
'ABI',
...]
list2 = [('A', 'B', 'C'),
('A', 'B', 'D'),
('A', 'B', 'E'),
('A', 'B', 'F'),
('A', 'B', 'G'),
('A', 'B', 'I'),
...]
Both the Lists are 2D because they return the same result on the same operation.
list1[0][1] returns 'B'
list2[0][1] also returns 'B'
What is the difference between list1 and list2 if they return the same result? How do I convert list2 in the format of list1?
Thank you.
The first list is list of strings and second list is list of tuples containing strings.
To convert list2 to list1 you can use:
list2 = [('A', 'B', 'C'),
('A', 'B', 'D'),
('A', 'B', 'E'),
('A', 'B', 'F'),
('A', 'B', 'G'),
('A', 'B', 'I'),]
new_list = [''.join(v) for v in list2]
print(new_list)
Output:
['ABC', 'ABD', 'ABE', 'ABF', 'ABG', 'ABI']