I have a dictionary
d_1 = { 'b':2, 'c':3, 'd':6}
How can I create a list of dictionaries by taking the combinations of the elements of dictionary as dictionary? Ex:
combs = [{'b':2}, { 'c':3}, {'d':6}, {'b':2, 'c':3}, {'c':3, 'd':6}, {'b':2, 'd':6}, { 'b':2, 'c':3, 'd':6}]
Use the below loop, in simply get all the numbers from range: [1, 2, 3], then simply use itertools.combinations and extend to fit them in, also than get the dictionary not with tuple at the end:
ld_1 = [{k:v} for k,v in d_1.items()]
l = []
for i in range(1, len(ld_1) + 1):
l.extend(list(itertools.combinations(ld_1, i)))
print([i[0] for i in l])
Using combinations from itertools:
[{i:d_1[i] for i in x} for x in chain.from_iterable(combinations(d_1, r) for r in range(1,len(d_1)+1))]
If what you want is a powerset you need to include the empty dictionary, too:
[{i:d_1[i] for i in x} for x in chain.from_iterable(combinations(d_1, r) for r in range(len(d_1)+1))]
(see itertools recipes)
You can try this:
from itertools import chain, combinations
def powerset(iterable):
"""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(1, len(s) + 1))
d_1 = {'b': 2, 'c': 3, 'd': 6}
comb = list(map(dict, powerset(d_1.items())))
print(comb)
Output:
[{'b': 2}, {'c': 3}, {'d': 6}, {'b': 2, 'c': 3}, {'b': 2, 'd': 6}, {'c': 3, 'd': 6}, {'b': 2, 'c': 3, 'd': 6}]
Related
I am trying to transform a dictionary of sets as the values with duplication to a dictionary with the unique sets as the value and at the same time join the keys together.
dic = {'a': {1, 2, 3}, 'b': {1, 2}, 'c': {1, 3, 2}, 'd': {1, 2, 3}}
Should be changed to
{'a-c-d': {1, 2, 3}, 'b': {1, 2}}
My try is as below, but I think there has to be a better way.
def transform_dictionary(dic: dict) -> dict:
dic = {k: frozenset(v) for k, v in dic.items()}
key_list = list(dic.keys())
value_list = list(dic.values())
dict_transformed = {}
for v_uinque in set(value_list):
sub_key_list = []
for i, v in enumerate(value_list):
if v == v_uinque:
sub_key_list.append(str(key_list[i]))
dict_transformed['-'.join(sub_key_list)] = set(v_uinque)
return dict_transformed
print(transform_dictionary(dic))
You can "invert" the input dictionary into a dictionary mapping frozensets into a set of keys.
import collections
dic = {'a': {1, 2, 3}, 'b': {1, 2}, 'c': {1, 3, 2}, 'd': {1, 2, 3}}
keys_per_set = collections.defaultdict(list)
for key, value in dic.items():
keys_per_set[frozenset(value)].append(key)
Then invert that dictionary mapping back into the desired form:
{'-'.join(keys): value for (value, keys) in keys_per_set.items()}
Output:
{'a-c-d': frozenset({1, 2, 3}), 'b': frozenset({1, 2})}
This will turn the values into a frozenset, but you could "thaw" them with a set(value) in the last list comprehension.
from itertools import groupby
dic_output = {'-'.join(v):g for g,v in groupby(sorted(dic_input,
key=dic_input.get),
key=lambda x: dic_input[x])}
Output
{'b': {1, 2}, 'a-c-d': {1, 2, 3}}
suppose I have a dictionary:
a_dic = {'file1':["a","b","c"],
'file2':["b","c","d"],
'file3':["c","d","e"]}
I want to write a function to be able to return a dictionary/dataframe to find the occurrence of the keys like:
occurrence = {'a':1, 'b':2, 'c':3, 'd':2,'e':1}
With collections.Counter object and itertools.chain.from_iterable function:
import collections, itertools
a_dic = {'file1':["a","b","c"], 'file2':["b","c","d"], 'file3':["c","d","e"]}
result = dict(collections.Counter(itertools.chain.from_iterable(a_dic.values())))
print(result)
The output:
{'c': 3, 'e': 1, 'b': 2, 'd': 2, 'a': 1}
from collections import Counter
flat_list = [item for sublist in (a_dic.values()) for item in sublist]
print(Counter(flat_list))
Output
Counter({'c': 3, 'b': 2, 'd': 2, 'a': 1, 'e': 1})
Assuming that there are two python list with the same structure like this:
var1 = [{'a':1,'b':2},{'c':2,'d':5,'h':4},{'c':2,'d':5,'e':4}]
var2 = [{'a':3,'b':2},{'c':1,'d':5,'h':4},{'c':5,'d':5,'e':4}]
In my case, i need to combine both of those list, so i'll get this value :
result = [{'a':4,'b':4},{'c':3,'d':10,'h':8},{'c':7,'d':10,'e':8}]
How can i do that?
zip-based one-liner comprehension:
result = [{k: d1[k]+d2[k] for k in d1} for d1, d2 in zip(var1, var2)]
This assumes that two dicts at the same index always have identical key sets.
Use list comprehensions to put the code in one line,
result = [{key : d1.get(key, 0)+d2.get(key, 0)
for key in set(d1.keys()) | set(d2.keys())} # union two sets
for d1, d2 in zip(var1, var2)]
print(result)
[{'a': 4, 'b': 4}, {'h': 8, 'c': 3, 'd': 10}, {'c': 7, 'e': 8, 'd': 10}]
This code takes into consideration the case that two dictionaries may not have the same keys.
var1 = [{'a':1,'b':2},{'c':2,'d':5,'h':4},{'c':2,'d':5,'e':4}]
var2 = [{'a':3,'b':2},{'c':1,'d':5,'h':4},{'c':5,'d':5,'e':4}]
res = []
for i in range(len(var1)):
dic = {}
dic1, dic2 = var1[i], var2[i]
for key, val in dic1.items(): // dic1.iteritems() in python 2.
dic[key] = dic1[key] + dic2[key]
res.append(dic)
>>>print(res)
[{'a': 4, 'b': 4}, {'c': 3, 'd': 10, 'h': 8}, {'c': 7, 'd': 10, 'e': 8}]
var1 = [{'a': 1, 'b': 2}, {'c': 2, 'd': 5, 'h': 4}, {'c': 2, 'd': 5, 'e': 4}]
var2 = [{'a': 3, 'b': 2}, {'c': 1, 'd': 5, 'h': 4}, {'c': 5, 'd': 5, 'e': 4}]
ret = []
for i, ele in enumerate(var1):
d = {}
for k, v in ele.items():
value = v
value += var2[i][k]
d[k] = value
ret.append(d)
print(ret)
For the sake of completeness, another zip-based one-liner that will work even if the dicts are uneven in the both lists:
result = [{k: d1.get(k, 0) + d2.get(k, 0) for k in set(d1) | set(d2)} for d1, d2 in zip(var1, var2)]
Would something like this help?
ar1 = [{'a':1,'b':2},{'c':2,'d':5,'h':4},{'c':2,'d':5,'e':4}]
var2 = [{'a':3,'b':2},{'c':1,'d':5,'h':4},{'c':5,'d':5,'e':4}]
combined_var = zip(var1, var2)
new_d = {}
list_new_ds = []
for i, j in combined_var:
new_d = {}
for key in i and j:
new_d[key] = i[key] + j[key]
list_new_ds.append(new_d)
list_new_ds = [{'a': 4, 'b': 4}, {'h': 8, 'c': 3, 'd': 10}, {'c': 7, 'e': 8, 'd': 10}]
To explain, the zip function merges the lists as a list of tuples. I then unpack the tuples and iterate through the keys in each dictionary and add the values for the same keys together using a new dictionary to store them. I then append the value to a list, and then re-initialise the temporary dictionary to empty before looking at the next tuple in the zipped list.
The order is different due to dictionary behaviour I believe.
I am a novice, so would appreciate any critiques of my answer!
This may be a duplicate but the closest I could find was Comparing 2 lists consisting of dictionaries with unique keys in python which did not work for me.
So I have two lists of dictionaries.
y = [{'a': 3, 'b': 4, 'c': 5}, {'a': 1, 'b': 2, 'c': 3}]
y = [{'a': 4, 'b': 5, 'c': 6}, {'a': 1, 'b': 2, 'c': 3}]
How do I compare these two lists so my compare results in the intersection of the two lists. I can't convert it to set since it says unhashable type (dict)
Your question and it's title seem at odds with each other.
The intersection of the 2 lists would be the common elements of both list. The question title requests the elements that are not in both lists. Which is it that you want?
For the intersection, it is not very efficient (being O(n^2) in time), but this list comprehension will do it:
>>> a = [{'a': 3, 'b': 4, 'c': 5}, {'a': 1, 'b': 2, 'c': 3}]
>>> b = [{'a': 4, 'b': 5, 'c': 6}, {'a': 1, 'b': 2, 'c': 3}]
>>> [d for d in a if d in b]
[{'a': 1, 'b': 2, 'c': 3}]
y1 = [{'a': 3, 'b': 4, 'c': 5}, {'a': 1, 'b': 2, 'c': 3}]
y2 = [{'a': 4, 'b': 5, 'c': 6}, {'a': 1, 'b': 2, 'c': 3}]
print [x for x in y1 if x in y2] # prints [{'a': 1, 'c': 3, 'b': 2}]
A dict (or list) is not hashable, however, a tuple is. You can convert the list of dicts to a set of tuples. Perform the intersection and then convert back
the code to convert to a set-of-tuples
y_tupleset = set(tuple(sorted(d.items())) for d in y)
the code to convert back the intersected set-of-tuples to a list-of-dicts
y_dictlist = [dict(it) for it in list(y_tupleset)]
Thus, the full code would be:
y0 = [{'a': 3, 'b': 4, 'c': 5}, {'a': 1, 'b': 2, 'c': 3}]
y1 = [{'a': 4, 'b': 5, 'c': 6}, {'a': 1, 'b': 2, 'c': 3}]
y0_tupleset = set(tuple(sorted(d.items())) for d in y0)
y1_tupleset = set(tuple(sorted(d.items())) for d in y1)
y_inter = y0_tupleset.intersection(y1_tupleset)
y_inter_dictlist = [dict(it) for it in list(y_inter)]
print(y_inter_dictlist)
# prints the following line
[{'a': 1, 'c': 3, 'b': 2}]
edit: d.items() is valid on python3, for python2, it should be replaced with d.iteritems()
Pick your poison:
y1 = [{'a': 3, 'b': 4, 'c': 5}, {'a': 1, 'b': 2, 'c': 3}]
y2 = [{'a': 4, 'b': 5, 'c': 6}, {'a': 1, 'b': 2, 'c': 3}]
y3 = [{'a': 1, 'b': 2, 'c': 3}, {'a': 4, 'b': 2, 'c': 6}]
# Returns a list of keys that are in both dictionaries
def intersect_keys(d1, d2):
return [k for k in d1 if k in d2]
# Returns a list of values that are in both dictionaries
def intersect_vals(d1, d2):
return [v for v in d1.itervalues() if v in d2.itervalues()]
# Returns a list of (key,value) pairs that are in both dictionaries
def intersect_pairs(d1, d2):
return [(k,v) for (k,v) in d1.iteritems() if k in d2 and d2[k] == v]
print(intersect_keys(*y1)) # ['a', 'c', 'b']
print(intersect_vals(*y1)) # [3]
print(intersect_pairs(*y1)) # []
print(intersect_keys(*y2)) # ['a', 'c', 'b']
print(intersect_vals(*y2)) # []
print(intersect_pairs(*y2)) # []
print(intersect_keys(*y3)) # ['a', 'c', 'b']
print(intersect_vals(*y3)) # [2]
print(intersect_pairs(*y3)) # [('b', 2)]
Note: the examples compare the two elements of the y* list, which was how I interpreted your question. You could of course use something like:
print(intersect_pairs(y1[0], y2[0]))
To compute the intersection the first dictionary in the y1 and y2 lists.
I know that I can set a key-value pair by using
dict[key] = value
but I have a very long list of dicts of the type
dict = [{a:1, b:2, c:3, d:4},
{a:2, b:3, c:4, d:5},
{a:5, b:7, c:3, d:9}]
and I'd like to do something along the lines of
dict = map(lambda x: x['d'] <- x['d'] -1, dict)
how would I go about this? (This is a very simplified example so I'm not really trying to just subtract a number from all items by a particular key)
expected output would be in this case and not the general case I'm looking for
[{a:1, b:2, c:3, d:3},
{a:2, b:3, c:4, d:4},
{a:5, b:7, c:3, d:8}]
EDIT: 2
I believe the following does not work - so any similar solution would be helpful:
dict = map(lambda x: x.update(d, x[d] - 1), dict)
dicts = [{'a':1, 'b':2, 'c':3, 'd':4},
{'a':2, 'b':3, 'c':4, 'd':5},
{'a':5, 'b':7, 'c':3, 'd':9}]
for d in dicts:
d['d'] -= 1
Output:
In [94]: dicts
Out[94]:
[{'d': 3, 'b': 2, 'c': 3, 'a': 1},
{'d': 4, 'b': 3, 'c': 4, 'a': 2},
{'d': 8, 'b': 7, 'c': 3, 'a': 5}]
how about this: as exactly you said
>>> dicts = [{'a':1, 'b':2, 'c':3, 'd':4},
{'a':2, 'b':3, 'c':4, 'd':5},
{'a':5, 'b':7, 'c':3, 'd':9}]
>>> map(lambda x:x.update([('d',x['d']-1)]),dicts)
[None, None, None]
>>> dicts
[{'a': 1, 'c': 3, 'b': 2, 'd': 3}, {'a': 2, 'c': 4, 'b': 3, 'd': 4}, {'a': 5, 'c': 3, 'b': 7, 'd': 8}]
update will update the dictionary with (key,value) pair. Returns None
map is a way of transforming an iterable to a list by performing the same operation on every item from the iterable. I don't think that's what you want to do here, and it has confused you.
On the face of it (although you haven't mentioned what the real operation is that you want to perform) a simple for is all that is necessary:
dict_list = [
{'a': 1, 'b': 2, 'c': 3, 'd': 4},
{'a': 2, 'b': 3, 'c': 4, 'd': 5},
{'a': 5, 'b': 7, 'c': 3, 'd': 9},
]
for d in dict_list:
d['d'] -= 1
print(d)
output
{'a': 1, 'b': 2, 'c': 3, 'd': 3}
{'a': 2, 'b': 3, 'c': 4, 'd': 4}
{'a': 5, 'b': 7, 'c': 3, 'd': 8}
Using dict.__setitem__ and temporary list (or any other collection typer) trick:
>>> dicts = [{'a':1, 'b':2, 'c':3, 'd':4},
... {'a':2, 'b':3, 'c':4, 'd':5},
... {'a':5, 'b':7, 'c':3, 'd':9}]
>>> map(lambda d: [d.__setitem__('d', d['d'] - 1), d][1], dicts)
[{'a': 1, 'c': 3, 'b': 2, 'd': 3},
{'a': 2, 'c': 4, 'b': 3, 'd': 4},
{'a': 5, 'c': 3, 'b': 7, 'd': 8}]
Using simple for loop is moe recommended way. Especially there's a side effect in the function.
BTW, don't use dict as a variable name. It will shadows builtin function/type dict.
How about this:
my_dict = {k: f(v) for k, v in my_dict.iteritems()}
where f is whatever function you want.