All unique combinations of a set of sets of values - python

If I have an arbitrary amount of elements, each with a specified set of values, what can I do to get all possible combinations with a value from each element's set?
For example, let's say I have:
elems = {"A": (0, 1), "B": (-1, -5)}
What can I do to get the following?
({"A": 0, "B": -1}, {"A": 0, "B": -5}, {"A": 1, "B": -1}, {"A": 1, "B": -5})
Input/output don't need to use dicts, but I figured that's the easiest way to represent it.
Assume dict order matters.
I would like to know a way that:
Does not assume there are just 2 elements like in the example.
Does not assume the sets for all elements have an equal length.
It is somewhat like listing all inputs for a truth table.

You can use a nested list/dictionary comprehension, using itertools.product to generate all combinations of the values, and then ziping each result tuple from that to the keys to generate the key/value pairs to make up each dictionary result. Here's an example using a slightly more complicated version of your data:
import itertools
elems = {"A": (0, 1), "B": (-1, -5), "C": (1, 2, 3) }
keys = elems.keys()
res = [dict(zip(keys, p)) for p in itertools.product(*elems.values())]
Output:
[
{'A': 0, 'B': -1, 'C': 1},
{'A': 0, 'B': -1, 'C': 2},
{'A': 0, 'B': -1, 'C': 3},
{'A': 0, 'B': -5, 'C': 1},
{'A': 0, 'B': -5, 'C': 2},
{'A': 0, 'B': -5, 'C': 3},
{'A': 1, 'B': -1, 'C': 1},
{'A': 1, 'B': -1, 'C': 2},
{'A': 1, 'B': -1, 'C': 3},
{'A': 1, 'B': -5, 'C': 1},
{'A': 1, 'B': -5, 'C': 2},
{'A': 1, 'B': -5, 'C': 3}
]

Related

Find common elements and their frequency in list of dictionaries

I have multiple (~40) lists that contain dictionaries, that I would like to find
which are those list items (in this case dictionaries) that are common in all lists
how many times each unique item appears across all lists.
Some examples of the lists are:
a = [{'A': 0, 'B': 0},
{'A': 0, 'C': 1},
{'D': 1, 'C': 0},
{'D': 1, 'E': 0}]
b = [{'A': 0},
{'B': 0, 'C': 1},
{'D': 1, 'C': 0},
{'D': 1, 'E': 0}]
c = [{'C': 0},
{'B': 1},
{'D': 1, 'C': 0, 'E': 0},
{'D': 1, 'E': 0}]
What I tried so far, it is the following code, but it returned values that were not common in all lists...
def flatten(map_groups):
items = []
for group in map_groups:
items.extend(group)
return items
def intersection(map_groups):
unique = []
items = flatten(map_groups)
for item in items:
if item not in unique and items.count(item) > 1:
unique.append(item)
return unique
all_lists = [a,b,c]
intersection(all_lists)
What I would expect to get as a result would be:
1. {'D': 1, 'E': 0} as a common item in all lists
2. {'D': 1, 'E': 0}, 3
{'D': 1, 'C': 0}, 2
{'A': 0, 'B': 0}, 1
{'A': 0, 'C': 1}, 1
{'A': 0}, 1
{'B': 0, 'C': 1}, 1
{'C': 0},
{'B': 1},
{'D': 1, 'C': 0, 'E': 0}
To count things, python comes with a nice class: collections.Counter. Now the question is: What do you want to count?
For example, if you want to count the dictionaries that have the same keys and values, you can do something like this:
>>> count = Counter(tuple(sorted(x.items())) for x in a+b+c)
>>> count.most_common(3)
[((('C', 0), ('D', 1)), 2), ((('D', 1), ('E', 0)), 2), ((('A', 0), ('B', 0)), 1)]
The dictionaries here are converted to tuples with sorted items to make them comparable and hashable. Getting for example the 3 most common back as a list of dictionaries is also not too hard:
>>> [dict(x[0]) for x in count.most_common(3)]
[{'C': 0, 'D': 1}, {'D': 1, 'E': 0}, {'A': 0, 'B': 0}]
You can use a nested for loop:
a = [{'A': 0, 'B': 0},
{'A': 0, 'C': 1},
{'D': 1, 'C': 0},
{'D': 1, 'E': 1}]
b = [{'A': 0},
{'B': 0, 'C': 1},
{'D': 1, 'C': 0},
{'D': 1, 'E': 0}]
c = [{'C': 0},
{'B': 1},
{'D': 1, 'C': 0, 'E': 0},
{'D': 1, 'E': 0}]
abc_list = [*a, *b, *c]
abc = list()
for d in abc_list:
for i in abc:
if d == i[0]:
abc[abc.index(i)] = (d, i[1] + 1)
continue
abc.append((d, 1))
print(abc)
Output:
[({'A': 0, 'B': 0}, 1),
({'A': 0, 'C': 1}, 1),
({'D': 1, 'C': 0}, 2),
({'D': 1, 'E': 1}, 1),
({'A': 0}, 1),
({'B': 0, 'C': 1}, 1),
({'D': 1, 'E': 0}, 2),
({'C': 0}, 1),
({'B': 1}, 1),
({'D': 1, 'C': 0, 'E': 0}, 1)]
Explanation:
The line
[*a, *b, *c]
unpacks all the values in lists a, b and c into a single list, which \i named abc_list.
The continue statement where I put it means to directly continue to the next iteration of the inner for loop, without reaching abc.append((d, 1)).
The above output answers question 2. For question 1, we can use the built-in max() method on the abc list, with a custom key:
print(max(ABC, key=lambda x:x[1])[0])
Of course, it will only return one dictionary, {'D': 1, 'C': 0}. If you want to print out multiple dictionaries that appear the most frequently:
m = max(abc, key=lambda x:x[1])[1]
for d in abc:
if d[1] == m:
print(d[0])
Output:
{'D': 1, 'C': 0}
{'D': 1, 'E': 0}

circular changing of key values in python dict [duplicate]

This question already has answers here:
Rotate values of a dictionary
(6 answers)
Closed 2 years ago.
I have a dict :
d = {'a': 0, 'b': 1, 'c': 2, 'd': 3}
Is there any python API which allows getting the bellow result
API(d)... = {'a': 1, 'b': 2, 'c': 3, 'd': 0}
API(d)... = {'a': 2, 'b': 3, 'c': 0, 'd': 1}
API(d)... = {'a': 3, 'b': 0, 'c': 1, 'd': 2}
You can implement it simply without taking much help from any non-standard library, like :
def rotate(d):
keys = d.keys()
values = list(d.values())
values = values[1:] + values[:1]
d = dict(zip(keys, values))
return d
d = {'a': 0, 'b': 1, 'c': 2, 'd': 3}
d = rotate(d)
print(d)
d = rotate(d)
print(d)
d = rotate(d)
print(d)
d = rotate(d)
print(d)
Output :
{'a': 1, 'b': 2, 'c': 3, 'd': 0}
{'a': 2, 'b': 3, 'c': 0, 'd': 1}
{'a': 3, 'b': 0, 'c': 1, 'd': 2}
{'a': 0, 'b': 1, 'c': 2, 'd': 3}
You try this. Write a function which rotates the list in the clock-wise direction.
def API(d):
val=list(d.values())
val.append(val.pop(0))
return dict(zip(d,val))
d = {'a': 0, 'b': 1, 'c': 2, 'd': 3}
d= API(d)
# {'a': 1, 'b': 2, 'c': 3, 'd': 0}
d= API(d)
# {'a': 2, 'b': 3, 'c': 0, 'd': 1}
d= API(d)
# {'a': 3, 'b': 0, 'c': 1, 'd': 2}

Create list with all combination of dictionaries, where key only appears once

I tried different approaces with itertools, but just can't figure it out.
I need to find different combinations of dictionaries:
letters = ['a','b','c']
combinations = []
for i in range(3):
for t in letters:
one_combi = {str(t):i}
combinations.append(one_combi)
Now have a list of dictionaries {letter:number}
Now I need to create a list of combinations where the key (letter) only appear once.
Expected output looks something like this:
[{'a':0,'b':0,'c':0},
{'a':1,'b':0,'c':0},
{'a':1,'b':1,'c':0},
{'a':1,'b':1,'c':1},
{'a':2,'b':0,'c':0},
...
{'a':2,'b':2,'c':2}]
Would be great if someone can help me out on this one!
You can generate all combinations of integers from a range derived from the length of the input, and then use zip:
letters = ['a','b','c']
def combos(d, c = []):
if len(c) == len(d):
yield dict(zip(letters, c))
else:
for i in d:
yield from combos(d, c+[i])
print(list(combos(range(len(letters))))
Output:
[{'a': 0, 'b': 0, 'c': 0},
{'a': 0, 'b': 0, 'c': 1},
{'a': 0, 'b': 0, 'c': 2},
{'a': 0, 'b': 1, 'c': 0},
{'a': 0, 'b': 1, 'c': 1},
...
{'a': 2, 'b': 2, 'c': 2}]
What you are looking for is itertools.product
from itertools import product
lst = []
for a, b, c in product([0, 1, 2], repeat=3):
lst.append({'a': a, 'b': b, 'c': c})
print(lst)
Output:
[{'a': 0, 'b': 0, 'c': 0},
{'a': 0, 'b': 0, 'c': 1},
{'a': 0, 'b': 0, 'c': 2},
{'a': 0, 'b':1, 'c': 0},
{'a': 0, 'b': 1, 'c': 1},
{'a': 0, 'b': 1, 'c': 2},
{'a': 0, 'b': 2, 'c': 0},
{'a': 0, 'b': 2, 'c': 1},...
Update
We can compact everything into a single line using list comprehension.
letters = ['a','b','c']
lst = [dict(zip(letters, x)) for x in product(range(len(letters)), repeat=len(letters))]
print(lst)

Filter Dictionary keys of multilevel dictionary

I have the following dict structure:
{12345: {2006: [{'a': 1, 'b': 2}, {'a': 3, 'b': 4}, {'a': 1, 'b': 5}]}, 12346: {2007: [{'a': 2, 'b': 7}, {'a': 1, 'b': 9}, {'a': 1, 'b': 12}]}}
I want to be able to filter based on the keys of 'a' or 'b'
for example if 'a' is 1 the my filtered dict would look like:
{12345: {2006: [{'a': 1, 'b': 2}, {'a': 1, 'b': 5}]}, 12346: {2007: [{'a': 1, 'b': 9}, {'a': 1, 'b': 12}]}}
I have the following for loop which gets me down to where I have the inner dict's I want, but I am not sure how to put it back into a dict of the same structure.
d = {12345: {2006: [{'a': 1, 'b': 2}, {'a': 3, 'b': 4}, {'a': 1, 'b': 5}]}, 12346: {2007: [{'a': 2, 'b': 7}, {'a': 1, 'b': 9}, {'a': 1, 'b': 12}]}}
d_filter = {}
for item_code in d.keys():
for year in d[item_code]:
for item_dict in d[item_code][year]:
if item_dict['a'] == 1:
print(item_dict) # how to put this back in d_filter?
producing:
{'a': 1, 'b': 2}
{'a': 1, 'b': 5}
{'a': 1, 'b': 9}
{'a': 1, 'b': 12}
I am guessing there is a better way to filter that I can not find, or something with dictionary comprehension that my small mind can not grasp.
Any help would be appreciated.
Here's a dictionary comprehension that does just that; dct is your initial dictionary:
d = {k: {ky: [d for d in vl if d['a']==1] for ky, vl in v.items()}
for k, v in dct.items()}
print d
# {12345: {2006: [{'a': 1, 'b': 2}, {'a': 1, 'b': 5}]}, 12346: {2007: [{'a': 1, 'b': 9}, {'a': 1, 'b': 12}]}}
You can change the inner filter (i.e. d['a']==1) to the dict key and/or value of your choice.
You could do something like this:
filtered = {
item_code: {
year: [item for item in items if item['a'] == 1]
for year, items in years.items()
}
for item_code, years in d.items()
}
Which results in:
{12345: {2006: [{'a': 1, 'b': 2}, {'a': 1, 'b': 5}]},
12346: {2007: [{'a': 1, 'b': 9}, {'a': 1, 'b': 12}]}}

Using list comprehension to setup a list of unique dictionaries in Python

I have the following dictionary
stocklist = {'a': 0, 'b': 0, 'c': 0}
And I want to setup a grid of HEIGHT by WIDTH where each cell in the grid has it's own unique version of a stocklist with different values. Will this work?
stockmap = [[stocklist for w in range(WIDTH)] for h in range(HEIGHT)]
I have other lists of width by height where each cell contains only one value, and they work fine.
But previous to this I tried to solve my issue by using Classes and it was a nightmare as my instances contained a list that kept being identical.
I'm worried that if I start coding the above I'll end up with the same problem.
In your example each 'cell' of your grid will point to the same dictionary - stocklist. So if you modify one 'cell' actually all of them will change.
If you need to store different dict in each cell you should create deep copies of the stocklist.
try:
import copy
stocklist = {'a': 0, 'b': 0, 'c': 0}
stockmap = [[copy.deepcopy(stocklist) for w in range(WIDTH)] for h in range(HEIGHT)]
In the simple example, where your stocklist does not contain any nested dict also
`stockmap = [[dict(stocklist) for w in range(WIDTH)] for h in range(HEIGHT)]`
will work. However remember that if your stocklist would be something like {'a': 0, 'b': {'c': 0}}, the internal - nested dict {'c': 0} will not be deep copied and each 'cell' will share that dict.
As I suggested above, you need to instantiate a new object, for example using dict
stockmap = [[dict(stocklist) for w in range(WIDTH)] for h in range(HEIGHT)]
otherwise the very same dictionary instance would be used.
Let's check it out:
with your example
>>> HEIGHT = 3
>>> WIDTH = 3
>>> stocklist = {'a': 0, 'b': 0, 'c': 0}
>>> stockmap = [[stocklist for w in range(WIDTH)] for h in range(HEIGHT)]
>>> stockmap
[[{'a': 0, 'b': 0, 'c': 0}, {'a': 0, 'b': 0, 'c': 0}, {'a': 0, 'b': 0, 'c': 0}], [{'a': 0, 'b': 0, 'c': 0}, {'a': 0, 'b': 0, 'c': 0}, {'a': 0, 'b': 0, 'c': 0}], [{'a': 0, 'b': 0, 'c': 0}, {'a': 0, 'b': 0, 'c': 0}, {'a': 0, 'b': 0, 'c': 0}]]
>>> stocklist['a']=9
>>> stockmap
[[{'a': 9, 'b': 0, 'c': 0}, {'a': 9, 'b': 0, 'c': 0}, {'a': 9, 'b': 0, 'c': 0}], [{'a': 9, 'b': 0, 'c': 0}, {'a': 9, 'b': 0, 'c': 0}, {'a': 9, 'b': 0, 'c': 0}], [{'a': 9, 'b': 0, 'c': 0}, {'a': 9, 'b': 0, 'c': 0}, {'a': 9, 'b': 0, 'c': 0}]]
as you can clearly see, modifying one item in the original dictionary affects the newly created list (grid)
Whereas doing
>>> stockmap = [[dict(stocklist) for w in range(WIDTH)] for h in range(HEIGHT)]
>>> stockmap
[[{'a': 9, 'b': 0, 'c': 0}, {'a': 9, 'b': 0, 'c': 0}, {'a': 9, 'b': 0, 'c': 0}], [{'a': 9, 'b': 0, 'c': 0}, {'a': 9, 'b': 0, 'c': 0}, {'a': 9, 'b': 0, 'c': 0}], [{'a': 9, 'b': 0, 'c': 0}, {'a': 9, 'b': 0, 'c': 0}, {'a': 9, 'b': 0, 'c': 0}]]
>>> stocklist['a']=5
>>> stockmap
[[{'a': 9, 'b': 0, 'c': 0}, {'a': 9, 'b': 0, 'c': 0}, {'a': 9, 'b': 0, 'c': 0}], [{'a': 9, 'b': 0, 'c': 0}, {'a': 9, 'b': 0, 'c': 0}, {'a': 9, 'b': 0, 'c': 0}], [{'a': 9, 'b': 0, 'c': 0}, {'a': 9, 'b': 0, 'c': 0}, {'a': 9, 'b': 0, 'c': 0}]]
leaves the grid unaltered
Note: as #damgad correctly points out, dict would not work for nested dictionaries. In such cases you need to use copy.deepcopy

Categories