This question already has answers here:
How can I create a Set of Sets in Python?
(4 answers)
Closed 3 years ago.
If you have a list of sets like this:
a_list = [{'a'}, {'a'}, {'a', 'b'}, {'a', 'b'}, {'a', 'c', 'b'}, {'a', 'c', 'b'}]
How could one get the number of unique sets in the list?
I have tried:
len(set(a_list ))
I am getting the error:
TypeError: unhashable type: 'set'
Desired output in this case is: 3 as there are three unique sets in the list.
You can use a tuple:
a_list = [{'a'}, {'a'}, {'a', 'b'}, {'a', 'b'}, {'a', 'c', 'b'}, {'a', 'c', 'b'}]
result = list(map(set, set(map(tuple, a_list))))
print(len(result))
Output:
[{'a', 'b'}, {'a'}, {'c', 'a', 'b'}]
3
A less functional approach, perhaps a bit more readable:
result = [set(c) for c in set([tuple(i) for i in a_list])]
How about Converting to a tuple:
a_list = [{'a'}, {'a'}, {'a', 'b'}, {'a', 'b'}, {'a', 'c', 'b'}, {'a', 'c', 'b'}]
print(len(set(map(tuple, a_list))))
OUTPUT:
3
Related
I have a dataframe (but it also can be just sets/lists):
Group Letter
1 {a,b,c,d,e}
2 {b,c,d,e,f}
3 {b,c,d,f,g}
4 {a,b,c,f,g}
5 {a,c,d,e,h}
I want to add column with intersection of group 1-2, 1-2-3, 1-2-3-4, 1-2-3-4-5.
So it'll be sth like this:
Group Letter Intersection
1 {a,b,c,d,e} None
2 {b,c,d,e,f} {b,c,d,e}
3 {b,c,d,f,g} {b,c,d}
4 {a,b,c,f,g} {b,c}
5 {a,c,d,e,h} {c}
I've read abt np.intersect1d, set.intersection, so I can do an intersection of multiple sets.
But I don't know how to do it in smart way.
Can someone help me with this problem?
You might itertools.accumulate for this task as follows
import itertools
letters = [{"a","b","c","d","e"},{"b","c","d","e","f"},{"b","c","d","f","g"},{"a","b","c","f","g"},{"a","c","d","e","h"}]
intersections = list(itertools.accumulate(letters, set.intersection))
print(intersections)
output
[{'e', 'a', 'b', 'c', 'd'}, {'b', 'e', 'c', 'd'}, {'b', 'c', 'd'}, {'b', 'c'}, {'c'}]
Note first element is {'e', 'a', 'b', 'c', 'd'} rather than None, so you would need to alter intersections in that regard.
I have a list of column names, and a list of lists that I would like to turn into a nested dictionary, where each inner list contains the column names as keys. By applying the code below, I encounter the same problem as my real data - I get the right key:value pairs, but only for the very last list.
I thought the way I was trying was a pretty simple approach (too simple?). I'm open to any way to do this, preferably without the use of third party packages, but in the interest of learning would like to know why this doesn't work.
keys = [1, 2, 3]
list_of_lists = [['A', 'B', 'C'], ['D', 'E', 'F']]
for x in list_of_lists:
test = dict(zip(keys, x))
print(test)
Desired output:
{{1: 'A', 2: 'B', 3: 'C'}, {1: 'D', 2: 'E', 3: 'F'}}
Actual output:
{1: 'D', 2: 'E', 3: 'F'}
If what you want is indeed a list of dicts, a very simple one-liner:
keys = [1, 2, 3]
list_of_lists = [['A', 'B', 'C'], ['D', 'E', 'F']]
print([dict(zip(keys, values)) for values in list_of_lists])
# [{1: 'A', 2: 'B', 3: 'C'}, {1: 'D', 2: 'E', 3: 'F'}]
keys = [1, 2, 3]
list_of_lists = [['A', 'B', 'C'], ['D', 'E', 'F']]
test = []
for x in list_of_lists:
test.append(dict(zip(keys, x)))
print(test)
This gives the list of dictionaries.
Output:
[{1: 'A', 2: 'B', 3: 'C'}, {1: 'D', 2: 'E', 3: 'F'}]
Nested dictionaries would require you to have key for each inner element. In the below example, I'm using count as key.
keys = [1, 2, 3]
list_of_lists = [['A', 'B', 'C'], ['D', 'E', 'F']]
test = {}
count = 0
for x in list_of_lists:
test[count] = dict(zip(keys, x))
count = count + 1
print(test)
Output:
{0: {1: 'A', 2: 'B', 3: 'C'}, 1: {1: 'D', 2: 'E', 3: 'F'}}
Unfortunately what you’re desired output shows is a set of dicts, and with a dict being unhashable this will not work.
Alternatively you could make a list or tuple of dicts:
test = [{k:v for k, v in zip(keys, l)} for l in list_of_lists]
#[{1: 'A', 2: 'B', 3: 'C'}, {1: 'D', 2: 'E', 3: 'F'}]
Or a dict of dicts, the keys for the outer dict being an enumeration of the outer list
test = {i: {k:v for k, v in zip(keys, l)} for i, l in enumerate(list_of_lists)}
#{0: {1: 'A', 2: 'B', 3: 'C'}, 1: {1: 'D', 2: 'E', 3: 'F'}}
You are better off placing your dictionaries in a list.
[dict(zip(keys, x)) for x in list_of_lists]
I am not sure, perhaps you would be interested in the order and then you might want to try
{i:x for i, x in zip(range(len(list_of_lists)), list_of_lists)}
Hope this helps
Edit:
Changed the dictionary response code
I am working on social media mutual friend problem and I choose to represent them using a dictionary. I am stuck at the part where you take a pair of users say a and b and create a set having union of their friend lists, something like
ab -> [{b,c,d,e},{c,d,a}]
NOTE: the code below says there is a user and he has some friends which are stored in a dictionary.
Now I want to pair each user with every other user in their friend list and create a list of sets which will have friend lists of both the users.
users = {
'a': ['b', 'c', 'd', 'e'],
'b': ['c', 'd', 'a'],
'c': ['a', 'b'],
'd': ['a','b','e'],
'e': ['a','d']
}
You can convert the dict of lists to a dict of sets, so that you can use set intersection for each combination of two users returned by itertools.combinations to find their mutual friends, and form a dict of sets indexed by frozensets of user pairs:
from itertools import combinations
u = {k: set(l) for k, l in users.items()}
{frozenset((a, b)): u[a] & u[b] for a, b in combinations(u, 2)}
This returns:
{frozenset({'b', 'a'}): {'c', 'd'},
frozenset({'a', 'c'}): {'b'},
frozenset({'a', 'd'}): {'b', 'e'},
frozenset({'a', 'e'}): {'d'},
frozenset({'b', 'c'}): {'a'},
frozenset({'b', 'd'}): {'a'},
frozenset({'b', 'e'}): {'a', 'd'},
frozenset({'c', 'd'}): {'b', 'a'},
frozenset({'c', 'e'}): {'a'},
frozenset({'e', 'd'}): {'a'}}
How can I create a permutation mapping of two lists in python?
For example I have two lists [1,2,3] and ['A','B','C']
Then my code should generate a list of 6 dictionaries
[ {1:'A',2:'B',3:'C'},
{1:'A',2:'C',3:'B'},
{1:'B',2:'A',3:'C'},
{1:'B',2:'C',3:'A'},
{1:'C',2:'A',3:'B'},
{1:'C',2:'B',3:'A'} ]
Using zip and itertools.permutations in a list comprehension:
>>> from itertools import permutations
>>> L1 = [1,2,3]
>>> L2 = ['A','B','C']
>>> [dict(zip(L1, p)) for p in permutations(L2)]
[{1: 'A', 2: 'B', 3: 'C'},
{1: 'A', 2: 'C', 3: 'B'},
{1: 'B', 2: 'A', 3: 'C'},
{1: 'B', 2: 'C', 3: 'A'},
{1: 'C', 2: 'A', 3: 'B'},
{1: 'C', 2: 'B', 3: 'A'}]
You seem to permutate only the values of the dicts, so you could do something like
from itertools import permutations
dicts = []
keys = [1, 2, 3]
for values in permutations(['A', 'B', 'C']):
new_dict = dict(zip(keys, values))
dicts.append(new_dict)
I know this is possible with list comprehension but I can't seem to figure it out. Currently I have a list of dictionaries like so:
[ {'field1': 'a', 'field2': 'b'},
{'field1': 'c', 'field2': 'd'},
{'field1': 'e', 'field2': 'f'} ]
I'm trying to turn this into:
list = [
['b', 'a'],
['d', 'c'],
['f', 'e'],
]
You can try:
[[x['field2'], x['field1']] for x in l]
where l is your input list. The result for your data would be:
[['b', 'a'], ['d', 'c'], ['f', 'e']]
This way you ensure that the value for field2 comes before the value for field1
Just return the dict.values() lists in Python 2, or convert the dictionary view to a list in Python 3:
[d.values() for d in list_of_dicts] # Python 2
[list(d.values()) for d in list_of_dicts] # Python 3
Note that the values are not going to be in any specific order, because dictionaries are not ordered. If you expected them to be in a given order you'd have to add a sorting step.
I'm not sure what ordering you want, but for no order you could do:
list_ = [list(_.values()) for _ in dict_list]
You can use list comprehension
Python 3
>>>listdict = [ {'field1': 'a', 'field2': 'b'},
... {'field1': 'c', 'field2': 'd'},
... {'field1': 'e', 'field2': 'f'} ]
>>>[[a for a in dict.values()] for dict in listdict]
[['b', 'a'], ['d', 'c'], ['f', 'e']]
Python 2
>>>[dict.values() for dict in listdict]
[['b', 'a'], ['d', 'c'], ['f', 'e']]