Related
I have a dict I'm trying to loop through which stores integer values:
myDict = {"a":1,"b":2,"c":3}
And I'm trying to loop through every combination of these integers from 1 to their value. For example:
{"a":1,"b":1,"c":1}
{"a":1,"b":1,"c":2}
{"a":1,"b":1,"c":3}
{"a":1,"b":2,"c":1}
{"a":1,"b":2,"c":2}
And so on...
Ending at their max values at the start while going through all the combinations.
Is there an elegant way to this that applies to any size dictionary? :
myDict = {"a":1,"b":2,"c":3,"d":5}
I'm currently doing this with nested if statements that edit a clone dictionary, so any solution setting dict values would work :) :
copyDict["c"] = 2
Yes, this will do it, for any size input (that fits in memory, of course):
import itertools
myDict = {"a":1,"b":2,"c":3,"d":5}
keys = list(myDict.keys())
ranges = tuple(range(1,k+1) for k in myDict.values())
outs = [dict(zip(keys,s)) for s in itertools.product(*ranges)]
print(outs)
You can actually replace *ranges with the *(range(1,k+1) for k in myDict.values()) and reduce it by one line, but it's not easier to read.
Another way with itertools.product:
>>> [dict(zip(myDict.keys(), p)) for p in itertools.product(myDict.values(), repeat=len(myDict))]
[{'a': 1, 'b': 1, 'c': 1},
{'a': 1, 'b': 1, 'c': 2},
{'a': 1, 'b': 1, 'c': 3},
{'a': 1, 'b': 2, 'c': 1},
{'a': 1, 'b': 2, 'c': 2},
{'a': 1, 'b': 2, 'c': 3},
{'a': 1, 'b': 3, 'c': 1},
{'a': 1, 'b': 3, 'c': 2},
{'a': 1, 'b': 3, 'c': 3},
{'a': 2, 'b': 1, 'c': 1},
{'a': 2, 'b': 1, 'c': 2},
{'a': 2, 'b': 1, 'c': 3},
{'a': 2, 'b': 2, 'c': 1},
{'a': 2, 'b': 2, 'c': 2},
{'a': 2, 'b': 2, 'c': 3},
{'a': 2, 'b': 3, 'c': 1},
{'a': 2, 'b': 3, 'c': 2},
{'a': 2, 'b': 3, 'c': 3},
{'a': 3, 'b': 1, 'c': 1},
{'a': 3, 'b': 1, 'c': 2},
{'a': 3, 'b': 1, 'c': 3},
{'a': 3, 'b': 2, 'c': 1},
{'a': 3, 'b': 2, 'c': 2},
{'a': 3, 'b': 2, 'c': 3},
{'a': 3, 'b': 3, 'c': 1},
{'a': 3, 'b': 3, 'c': 2},
{'a': 3, 'b': 3, 'c': 3}]
I'm relatively new to programming and I'm quite stuck.
I have a dictionary like this below. I want to say like
n = "a"
then I want to remove every variable n from the dictionary.
Then I want to remove every letter a that is in this nested dictionary below. I know how to remove stuff from dictionaries to a tiny extent, but I'm quite confused right now as I don't know how to do it with a nested dictionary. In this case, there's a key and then a value but inside the value is another dictionary with other keys and values. I have implemented for loops etc. to try and do what I want to do but the solution I get isn't what I'm looking for.
Thank you:)
{'b': {'a': 7, 'c': 10, 'd': 15}, 'a': {'b': 7, 'c': 9, 'f': 14}, 'c': {'a': 9, 'b': 10, 'd': 11, 'f': 2}, 'f': {'a': 14, 'c': 2, 'e': 9}, 'd': {'b': 15, 'c': 11, 'e': 6}, 'e': {'d': 6, 'f': 9}}
dic = {'b': {'a': 7, 'c': 10, 'd': 15}, 'a': {'b': 7, 'c': 9, 'f': 14}, 'c': {'a': 9, 'b': 10, 'd': 11, 'f': 2}, 'f': {'a': 14, 'c': 2, 'e': 9}, 'd': {'b': 15, 'c': 11, 'e': 6}, 'e': {'d': 6, 'f': 9}}
This is what I have so far, but it's just removing the first b which is a key, how do i access the b's inside the nested dictionary
n = "b"
del dic[n]
print(dic)
and whenever I do something like :
dic = {'b': {'a': 7, 'c': 10, 'd': 15}, 'a': {'b': 7, 'c': 9, 'f': 14}, 'c': {'a': 9, 'b': 10, 'd': 11, 'f': 2}, 'f': {'a': 14, 'c': 2, 'e': 9}, 'd': {'b': 15, 'c': 11, 'e': 6}, 'e': {'d': 6, 'f': 9}}
and whenever I do something like:
n = "b"
for k in dic.keys():
if k == n:
del dic[k]
it comes up in the terminal that RuntimeError: dictionary changed size during iteration
You could write a recursive function:
def delete_key(k, dic):
if k in dic:
del dic[k]
for val in dic.values():
if isinstance(val, dict):
delete_key(k, val)
return dic
d = {'b': {'a': 7, 'c': 10, 'd': 15}, 'a': {'b': 7, 'c': 9, 'f': 14}, 'c': {'a': 9, 'b': 10, 'd': 11, 'f': 2}, 'f': {'a': 14, 'c': 2, 'e': 9}, 'd': {'b': 15, 'c': 11, 'e': 6}, 'e': {'d': 6, 'f': 9}}
delete_key('b', d)
{'a': {'c': 9, 'f': 14},
'c': {'a': 9, 'd': 11, 'f': 2},
'd': {'c': 11, 'e': 6},
'e': {'d': 6, 'f': 9},
'f': {'a': 14, 'c': 2, 'e': 9}}
Assuming you want to convert the dictionary to a matrix, you can do this as follows:
from sklearn.feature_extraction import DictVectorizer
dictionary = {
'b': {'a': 7, 'c': 10, 'd': 15},
'a': {'b': 7, 'c': 9, 'f': 14},
'c': {'a': 9, 'b': 10, 'd': 11, 'f': 2},
'f': {'a': 14, 'c': 2, 'e': 9},
'd': {'b': 15, 'c': 11, 'e': 6},
'e': {'d': 6, 'f': 9}
}
keys_removed = [dictionary.get(i) for i in dictionary]
dictvectorizer = DictVectorizer(sparse=False)
matrix = dictvectorizer.fit_transform(keys_removed)
This will provide the following output:
[[ 7. 0. 10. 15. 0. 0.]
[ 0. 7. 9. 0. 0. 14.]
[ 9. 10. 0. 11. 0. 2.]
[14. 0. 2. 0. 9. 0.]
[ 0. 15. 11. 0. 6. 0.]
[ 0. 0. 0. 6. 0. 9.]]
With matrix indices corresponding to the inner key values (a to f), which is why the matrix has zeroes where a value does not exist at a specific key.
Alternatively, if you just want to get rid of the main keys, you simply need to use keys_removed = [dictionary.get(i) for i in dictionary] and convert it from a list.
This will give you the following:
[{'a': 7, 'c': 10, 'd': 15}, {'b': 7, 'c': 9, 'f': 14}, {'a': 9, 'b': 10, 'd': 11, 'f': 2}, {'a': 14, 'c': 2, 'e': 9}, {'b': 15, 'c': 11, 'e': 6}, {'d': 6, 'f': 9}]
EDIT
If you want to delete certain keys and their corresponding entries, you could do something like this:
def delete_key(keys: list):
dictionary = {
'b': {'a': 7, 'c': 10, 'd': 15},
'a': {'b': 7, 'c': 9, 'f': 14},
'c': {'a': 9, 'b': 10, 'd': 11, 'f': 2},
'f': {'a': 14, 'c': 2, 'e': 9},
'd': {'b': 15, 'c': 11, 'e': 6},
'e': {'d': 6, 'f': 9}
}
for i in keys:
dictionary.pop(i)
return dictionary
print (delete_key(keys=['a', 'c']))
This takes a list of keys that you want to delete and returns a new dictionary without them. The above case outputs:
{'b': {'a': 7, 'c': 10, 'd': 15}, 'f': {'a': 14, 'c': 2, 'e': 9}, 'd': {'b': 15, 'c': 11, 'e': 6}, 'e': {'d': 6, 'f': 9}}
According to your recent clarifications, this should work:
def delete_key(outer_keys: list, inner_keys: list):
dictionary = {
'b': {'a': 7, 'c': 10, 'd': 15},
'a': {'b': 7, 'c': 9, 'f': 14},
'c': {'a': 9, 'b': 10, 'd': 11, 'f': 2},
'f': {'a': 14, 'c': 2, 'e': 9},
'd': {'b': 15, 'c': 11, 'e': 6},
'e': {'d': 6, 'f': 9}
}
for i in outer_keys:
dictionary.pop(i)
for i in dictionary:
for j in inner_keys:
if j in dictionary[i]:
dictionary[i].pop(j)
return dictionary
print (delete_key(outer_keys=[], inner_keys=['a']))
The function works as follows:
It allows you to specify which keys (and corresponding entries) you want removed. You simply list which in either outer_keys or inner_keys, the latter being the deepest keys in the nested dictionary.
These have to be defined as a list of the key names and can be empty if you want to only remove the keys from the inner or outer.
The above example will output the following:
{'b': {'c': 10, 'd': 15}, 'a': {'b': 7, 'c': 9, 'f': 14}, 'c': {'b': 10, 'd': 11, 'f': 2}, 'f': {'c': 2, 'e': 9}, 'd': {'b': 15, 'c': 11, 'e': 6}, 'e': {'d': 6, 'f': 9}}
You will notice that all of the inner 'a' keys have been removed. The operation can be done using fewer loops, but this should illustrate the process well enough.
I have some code that generates all the combinations for a dictionary of lists
import itertools
import collections
def gen_combinations(d):
keys, values = d.keys(), d.values()
combinations = itertools.product(*values)
for c in combinations:
yield dict(zip(keys, c))
Let's say I have a dictionary A like
A = {'a': [0, 1],
'b': [2, 3, 4]}
It yields:
{'a': 0, 'b': 2}
{'a': 0, 'b': 3}
{'a': 0, 'b': 4}
{'a': 1, 'b': 2}
{'a': 1, 'b': 3}
{'a': 1, 'b': 4}
Now I'd like it to work with nested dictionary of lists like
B = {'s1': {'a': [0, 1],
'b': [0, 1, 2] },
's2': {'c': [0, 1],
'd': [0, 1] }}
which should yield something like:
{'s1': {'a': 0, 'b': 0},
's2': {'c': 0, 'd': 0}}
{'s1': {'a': 0, 'b': 0},
's2': {'c': 0, 'd': 1}}
{'s1': {'a': 0, 'b': 0},
's2': {'c': 1, 'd': 0}}
{'s1': {'a': 0, 'b': 0},
's2': {'c': 1, 'd': 1}}
and so on for all the combinations...
I'm looking for an elegant way to do this. Don't have any particular performance restrictions, they are small dictionaries.
Just create the product of the output of gen_combinations() for each key in the outer dictionary:
def gen_dict_combinations(d):
keys, values = d.keys(), d.values()
for c in itertools.product(*(gen_combinations(v) for v in values)):
yield dict(zip(keys, c))
This is basically the same pattern, only now instead of using values directly, we use the output of gen_combinations():
>>> for c in gen_dict_combinations(B):
... print(c)
...
{'s1': {'a': 0, 'b': 0}, 's2': {'c': 0, 'd': 0}}
{'s1': {'a': 0, 'b': 0}, 's2': {'c': 0, 'd': 1}}
{'s1': {'a': 0, 'b': 0}, 's2': {'c': 1, 'd': 0}}
{'s1': {'a': 0, 'b': 0}, 's2': {'c': 1, 'd': 1}}
{'s1': {'a': 0, 'b': 1}, 's2': {'c': 0, 'd': 0}}
{'s1': {'a': 0, 'b': 1}, 's2': {'c': 0, 'd': 1}}
{'s1': {'a': 0, 'b': 1}, 's2': {'c': 1, 'd': 0}}
{'s1': {'a': 0, 'b': 1}, 's2': {'c': 1, 'd': 1}}
{'s1': {'a': 0, 'b': 2}, 's2': {'c': 0, 'd': 0}}
{'s1': {'a': 0, 'b': 2}, 's2': {'c': 0, 'd': 1}}
{'s1': {'a': 0, 'b': 2}, 's2': {'c': 1, 'd': 0}}
{'s1': {'a': 0, 'b': 2}, 's2': {'c': 1, 'd': 1}}
{'s1': {'a': 1, 'b': 0}, 's2': {'c': 0, 'd': 0}}
{'s1': {'a': 1, 'b': 0}, 's2': {'c': 0, 'd': 1}}
{'s1': {'a': 1, 'b': 0}, 's2': {'c': 1, 'd': 0}}
{'s1': {'a': 1, 'b': 0}, 's2': {'c': 1, 'd': 1}}
{'s1': {'a': 1, 'b': 1}, 's2': {'c': 0, 'd': 0}}
{'s1': {'a': 1, 'b': 1}, 's2': {'c': 0, 'd': 1}}
{'s1': {'a': 1, 'b': 1}, 's2': {'c': 1, 'd': 0}}
{'s1': {'a': 1, 'b': 1}, 's2': {'c': 1, 'd': 1}}
{'s1': {'a': 1, 'b': 2}, 's2': {'c': 0, 'd': 0}}
{'s1': {'a': 1, 'b': 2}, 's2': {'c': 0, 'd': 1}}
{'s1': {'a': 1, 'b': 2}, 's2': {'c': 1, 'd': 0}}
{'s1': {'a': 1, 'b': 2}, 's2': {'c': 1, 'd': 1}}
Ended up with a recursive version for arbitrarily nested dictionaries:
import itertools
def gen_combinations(d):
keys, values = d.keys(), d.values()
values_choices = (gen_combinations(v) if isinstance(v, dict) else v for v in values)
for comb in itertools.product(*values_choices):
yield dict(zip(keys, comb))
B = {'s1': {'a': [0, 1],
'b': [0, 1, 2] },
's2': {'c': [0, 1],
'd': [0, 1] }}
for c in gen_combinations(B):
print(c)
Output:
{'s1': {'a': 0, 'b': 0}, 's2': {'c': 0, 'd': 0}}
{'s1': {'a': 0, 'b': 0}, 's2': {'c': 0, 'd': 1}}
{'s1': {'a': 0, 'b': 0}, 's2': {'c': 1, 'd': 0}}
{'s1': {'a': 0, 'b': 0}, 's2': {'c': 1, 'd': 1}}
{'s1': {'a': 0, 'b': 1}, 's2': {'c': 0, 'd': 0}}
{'s1': {'a': 0, 'b': 1}, 's2': {'c': 0, 'd': 1}}
{'s1': {'a': 0, 'b': 1}, 's2': {'c': 1, 'd': 0}}
{'s1': {'a': 0, 'b': 1}, 's2': {'c': 1, 'd': 1}}
{'s1': {'a': 0, 'b': 2}, 's2': {'c': 0, 'd': 0}}
{'s1': {'a': 0, 'b': 2}, 's2': {'c': 0, 'd': 1}}
{'s1': {'a': 0, 'b': 2}, 's2': {'c': 1, 'd': 0}}
{'s1': {'a': 0, 'b': 2}, 's2': {'c': 1, 'd': 1}}
{'s1': {'a': 1, 'b': 0}, 's2': {'c': 0, 'd': 0}}
{'s1': {'a': 1, 'b': 0}, 's2': {'c': 0, 'd': 1}}
{'s1': {'a': 1, 'b': 0}, 's2': {'c': 1, 'd': 0}}
{'s1': {'a': 1, 'b': 0}, 's2': {'c': 1, 'd': 1}}
{'s1': {'a': 1, 'b': 1}, 's2': {'c': 0, 'd': 0}}
{'s1': {'a': 1, 'b': 1}, 's2': {'c': 0, 'd': 1}}
{'s1': {'a': 1, 'b': 1}, 's2': {'c': 1, 'd': 0}}
{'s1': {'a': 1, 'b': 1}, 's2': {'c': 1, 'd': 1}}
{'s1': {'a': 1, 'b': 2}, 's2': {'c': 0, 'd': 0}}
{'s1': {'a': 1, 'b': 2}, 's2': {'c': 0, 'd': 1}}
{'s1': {'a': 1, 'b': 2}, 's2': {'c': 1, 'd': 0}}
{'s1': {'a': 1, 'b': 2}, 's2': {'c': 1, 'd': 1}}
I extended Martijn Pieters answer so that the function can also handle non-iterable values in the nested dictionary. So the code below works on nested dicts (just one level of nesting though) that look like this:
dictionary = {
'a': 31415,
'b': 'strings too',
'c': [1, 2, 3],
'd': {'e': [1, 2, 3], 'f': 42, 'g': 'strings here too'}
}
from itertools import product
def _gen_combinations(d):
keys, values = d.keys(), d.values()
list_keys = [k for k in keys if isinstance(d[k], list)]
nonlist_keys = [k for k in keys if k not in list_keys]
list_values = [v for v in values if isinstance(v, list)]
nonlist_values = [v for v in values if v not in list_values]
combinations = product(*list_values)
for c in combinations:
result = dict(zip(list_keys, c))
result.update({k: v for k, v in zip(nonlist_keys, nonlist_values)})
yield result
def generate_dict_combinations(d):
keys, values = d.keys(), d.values()
dict_values = [v for v in values if isinstance(v, dict)]
dict_keys = [k for k in keys if isinstance(d[k], dict)]
nondict_values = [v for v in values if v not in dict_values]
nondict_keys = [k for k in keys if k not in dict_keys]
for c in product(*(_gen_combinations(v) for v in dict_values)):
result = dict(zip(dict_keys, c))
result.update({k: v for k, v in zip(nondict_keys, nondict_values)})
yield result
This question already has answers here:
How do I merge two dictionaries in a single expression in Python?
(43 answers)
Closed 5 years ago.
I have two lists of dictionaries which I am trying to get the product of:
from itertools import product
list1 = [{'A': 1, 'B': 1}, {'A': 2, 'B': 2}, {'A': 2, 'B': 1}, {'A': 1, 'B': 2}]
list2 = [{'C': 1, 'D': 1}, {'C': 1, 'D': 2}]
for p in product(list1, list2):
print p
and this gives me the output:
({'A': 1, 'B': 1}, {'C': 1, 'D': 1})
({'A': 1, 'B': 1}, {'C': 1, 'D': 2})
({'A': 2, 'B': 2}, {'C': 1, 'D': 1})
({'A': 2, 'B': 2}, {'C': 1, 'D': 2})
({'A': 2, 'B': 1}, {'C': 1, 'D': 1})
({'A': 2, 'B': 1}, {'C': 1, 'D': 2})
({'A': 1, 'B': 2}, {'C': 1, 'D': 1})
({'A': 1, 'B': 2}, {'C': 1, 'D': 2})
How would I flatten these so the output is a single dict rather than a tuple of dicts?:
{'A': 1, 'B': 1, 'C': 1, 'D': 1}
{'A': 1, 'B': 1, 'C': 1, 'D': 2}
{'A': 2, 'B': 2, 'C': 1, 'D': 1}
{'A': 2, 'B': 2, 'C': 1, 'D': 2}
{'A': 2, 'B': 1, 'C': 1, 'D': 1}
{'A': 2, 'B': 1, 'C': 1, 'D': 2}
{'A': 1, 'B': 2, 'C': 1, 'D': 1}
{'A': 1, 'B': 2, 'C': 1, 'D': 2}
Looks like you want to merge the dictionaries
for p1, p2 in product(list1, list2):
merged = {**p1, **p2}
print(merged)
In earlier versions of Python, you can't merge with this expression. Use p1.update(p2) instead.
What is the best way to sort a nested dictionary in Python 2.6 by value? I would like to sort by the length of the inner dictionary followed by the inner dictionary with the largest value. For example:
d = {1: {'AA': {'a': 100, 'b': 1, 'c': 45}},
2: {'AA': {'c': 2}},
3: {'BB': {'d': 122, 'a': 4, 't': 22, 'r': 23, 'w': 12}},
4: {'CC': {'y': 12, 'g': 15, 'b': 500}}}
The desired solution is a nested list:
lst = [[3, 'BB', {'d': 122, 'a': 4, 't': 22, 'r': 23, 'w': 12}],
[4, 'CC', {'y': 12, 'g': 15, 'b': 500}],
[1, 'AA', {'a': 100, 'b': 1, 'c': 45}],
[2, 'AA', {'c': 2}]]
With your corrected data-structure:
d = {1: {'AA': {'a': 100, 'b': 1, 'c': 45}},
2: {'AA': {'c': 2}},
3: {'BB': {'d': 122, 'a': 4, 't': 22, 'r': 23, 'w': 12}},
4: {'CC': {'y': 12, 'g': 15, 'b': 500}}}
def sortkey(x):
num,d1 = x
key,d2 = d1.items()[0] #Some may prefer `next(d.iteritems())`
return len(d2),max(d2.values())
exactly_how_you_want_it = [([k] + v.keys() + v.values()) for k,v in
sorted(d.items(),reverse=True,key=sortkey)]
for item in exactly_how_you_want_it:
print item
results:
[3, 'BB', {'a': 4, 'r': 23, 'd': 122, 'w': 12, 't': 22}]
[4, 'CC', {'y': 12, 'b': 500, 'g': 15}]
[1, 'AA', {'a': 100, 'c': 45, 'b': 1}]
[2, 'AA', {'c': 2}]