Cartesian product of a dictionary of lists
Ok, thanks @dfan for telling me I was looking in the wrong place. I've got it now:
from itertools import product
def my_product(inp):
return (dict(zip(inp.keys(), values)) for values in product(*inp.values())
EDIT: after years more Python experience, I think a better solution is to accept kwargs
rather than a dictionary of inputs; the call style is more analogous to that of the original itertools.product
. Also I think writing a generator function, rather than a function that returns a generator expression, makes the code clearer. So:def product_dict(**kwargs):
keys = kwargs.keys()
vals = kwargs.values()
for instance in itertools.product(*vals):
yield dict(zip(keys, instance))
and if you need to pass in a dict, list(product_dict(**mydict))
. The one notable change using kwargs
rather than an arbitrary input class is that it prevents the keys/values from being ordered, at least until Python 3.6. Cartesian product of a dictionary of lists - with sorting
If you're using Python 3.5 or later versions, you can make status
the first key in your dict instead:
d = {
"status": ["on", "off"],
"letters": ['a', 'b'],
"numbers": [1, 2, 3]
}
For earlier versions, use collections.OrderedDict
in place of a dict. Cartesian product of a dictionary of lists as items
import itertools
d = {
'variable_1': ['a1', 'b1', 'c1'],
'variable_2': ['a2', 'b2', 'c2'],
'variable_3': ['a3', 'b3', 'c3'],
}
keys = (list(d.keys())) # ['variable_1', 'variable_2', 'variable_3']
values = (list(itertools.product(*(list(d.values()))))) #[('a1', 'a2', 'a3'), ('a1', 'a2', 'b3'), ('a1', 'a2', 'c3')...]
dictionary = []
for val in values:
dictionary.append(dict(zip(keys, val)))
output:[{'variable_1': 'a1', 'variable_2': 'a2', 'variable_3': 'a3'}, {'variable_1': 'a1', 'variable_2': 'a2', 'variable_3': 'b3'}, {'variable_1': 'a1', 'variable_2': 'a2', 'variable_3': 'c3'}, {'variable_1': 'a1', 'variable_2': 'b2', 'variable_3': 'a3'},...]
exapmle:d = {
'variable_1': ['a1', 'b1', 'c1','d1'],
'variable_2': ['a2', 'b2', 'c2','d2'],
'variable_3': ['a3', 'b3', 'c3','d3'],
'variable_4': ['a3', 'b3', 'c3','d4'],
}
output:[{'variable_1': 'a1', 'variable_2': 'a2', 'variable_3': 'a3', 'variable_4': 'a3'}, {'variable_1': 'a1', 'variable_2': 'a2', 'variable_3': 'a3', 'variable_4': 'b3'}, {'variable_1': 'a1', 'variable_2': 'a2', 'variable_3': 'a3', 'variable_4': 'c3'}, {'variable_1': 'a1', 'variable_2': 'a2', 'variable_3': 'a3', 'variable_4': 'd4'}, ...]
Cartesian product of nested dictionaries of lists
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}}
How to get the cartesian product of a series of lists
Use itertools.product
, which has been available since Python 2.6.
import itertools
somelists = [
[1, 2, 3],
['a', 'b'],
[4, 5]
]
for element in itertools.product(*somelists):
print(element)
This is the same as:for element in itertools.product([1, 2, 3], ['a', 'b'], [4, 5]):
print(element)
Cartesian Product of Dictionary Keys and Values Python
Simple iteration through two dictionaries, adding tuple and absolute difference to another:
dic_courses = {'C1': 10, 'C2': 5, 'C3': 20}
dic_rooms = {'R1': 5, 'R2': 10, 'R3': 20}
d = {}
for k1, v1 in dic_courses.items():
for k2, v2 in dic_rooms.items():
d.update({(k1, k2): abs(v1 - v2)})
print(d)
# {('C1', 'R1'): 5, ('C1', 'R2'): 0, ('C1', 'R3'): 10,
# ('C2', 'R1'): 0, ('C2', 'R2'): 5, ('C2', 'R3'): 15,
# ('C3', 'R1'): 15, ('C3', 'R2'): 10, ('C3', 'R3'): 0}
Or itertools.product
way:from itertools import product
dic_courses = {'C1': 10, 'C2': 5, 'C3': 20}
dic_rooms = {'R1': 5, 'R2': 10, 'R3': 20}
d = {}
for x, y in product(dic_courses, dic_rooms):
d.update({(x, y): abs(dic_courses[x] - dic_rooms[y])})
print(d)
# {('C1', 'R1'): 5, ('C1', 'R2'): 0, ('C1', 'R3'): 10,
# ('C2', 'R1'): 0, ('C2', 'R2'): 5, ('C2', 'R3'): 15,
# ('C3', 'R1'): 15, ('C3', 'R2'): 10, ('C3', 'R3'): 0}
How do I get the cartesian product of a dictionary in a specific order?
I think this comes down to the order of arguments to the product function, which seems to determine the way that the arrays are cycled through when creating the cartesian product.
If you reverse the order of arrays in the input dictionary the outputs become the same. (This just seems to be the case for the difference between the two implementations in action here, so would be nice if someone had some more detailed insights.)
# reverse dictionary keys
reversed_cols = list(gas_dict.keys())[::-1]
# create reversed input dictionary
gas_dict_rev = {c: sorted(gas_dict[c]) for c in reversed_cols}
# create cartesian product with reversed column order
gas_product_rev = list(product_dict(**gas_dict_rev))
gas_product_rev = pd.DataFrame(gas_product_rev)
# change the column order to conform original dict
gas_product_rev = gas_product_rev[gas_dict.keys()]
the output then looks the same visually, but gas.equals(gas_product_rev)
still reports FALSE
for me. I'm not familiar with this function but I'd guess it does not take float precision into account. Checking with a numpy function that allows for float precision we get the expected result:for column in gas:
print(f'{column} {np.allclose(gas[column], gas_product[column])}')
# Velocity (m/s) False
# Pressure (Pa) False
# Temperature False
# Equivalence Ratio False
for column in gas:
print(f'{column} {np.allclose(gas[column], gas_product_rev[column])}')
# Velocity (m/s) True
# Pressure (Pa) True
# Temperature True
# Equivalence Ratio True
C# - create new lists from a dictionary of lists
Based on your example, what you are looking for is called the "cartesian product" of the dictionary's values. Eric Lippert has a series of blog posts about various ways of permuting and combining sets and sequences in C# including one about the generation of cartesian products via a linq extension method.
From the cited link, the following
public static class Program
{
static IEnumerable<IEnumerable<T>> CartesianProduct<T>(this IEnumerable<IEnumerable<T>> sequences)
{
IEnumerable<IEnumerable<T>> emptyProduct =
new[] { Enumerable.Empty<T>() };
return sequences.Aggregate(
emptyProduct,
(accumulator, sequence) =>
from accseq in accumulator
from item in sequence
select accseq.Concat(new[] { item }));
}
static void Main(string[] args)
{
var mappings = new Dictionary<string, List<string>> {
{ "Policy", new List<string> { "PlPolicy" } },
{ "Location", new List<string> { "L1", "L2" } },
{ "Claim", new List<string> { "C1", "C2", "C3" } }
};
foreach(var triple in CartesianProduct(mappings.Values)) {
Console.WriteLine( string.Join(" , ", triple) );
}
}
}
generatesPlPolicy , L1 , C1
PlPolicy , L1 , C2
PlPolicy , L1 , C3
PlPolicy , L2 , C1
PlPolicy , L2 , C2
PlPolicy , L2 , C3
Cartesian product giving a dictionary
Zip your values with the keys:
keys = 'brand', 'speed', 'model'
ll = [dict(zip(keys, combo)) for combo in product(brand, speed, model)]
Demo:>>> from itertools import product
>>> from pprint import pprint
>>> brand = ["Audi", "Mercedes"]
>>> speed = [130, 150]
>>> model = ["sport", "family"]
>>> keys = 'brand', 'speed', 'model'
>>> [dict(zip(keys, combo)) for combo in product(brand, speed, model)]
[{'speed': 130, 'brand': 'Audi', 'model': 'sport'}, {'speed': 130, 'brand': 'Audi', 'model': 'family'}, {'speed': 150, 'brand': 'Audi', 'model': 'sport'}, {'speed': 150, 'brand': 'Audi', 'model': 'family'}, {'speed': 130, 'brand': 'Mercedes', 'model': 'sport'}, {'speed': 130, 'brand': 'Mercedes', 'model': 'family'}, {'speed': 150, 'brand': 'Mercedes', 'model': 'sport'}, {'speed': 150, 'brand': 'Mercedes', 'model': 'family'}]
>>> pprint(_)
[{'brand': 'Audi', 'model': 'sport', 'speed': 130},
{'brand': 'Audi', 'model': 'family', 'speed': 130},
{'brand': 'Audi', 'model': 'sport', 'speed': 150},
{'brand': 'Audi', 'model': 'family', 'speed': 150},
{'brand': 'Mercedes', 'model': 'sport', 'speed': 130},
{'brand': 'Mercedes', 'model': 'family', 'speed': 130},
{'brand': 'Mercedes', 'model': 'sport', 'speed': 150},
{'brand': 'Mercedes', 'model': 'family', 'speed': 150}]
Related Topics
Django Post_Save() Signal Implementation
How to Exit from Python Without Traceback
Counting Cars Opencv + Python Issue
Detect Tap with Pyaudio from Live Mic
Why Does the Floating-Point Value of 4*0.1 Look Nice in Python 3 But 3*0.1 Doesn'T
Finding Number of Colored Shapes from Picture Using Python
Slicing of a Numpy 2D Array, or How to Extract an Mxm Submatrix from an Nxn Array (N>M)
Os.Path.Dirname(_File_) Returns Empty
How to Troubleshoot Python "Could Not Find Platform Independent Libraries <Prefix>"
Python: Can't Pickle Type X, Attribute Lookup Failed
Find Index of Last Occurrence of a Substring in a String
How to Tell Pycharm What Type a Parameter Is Expected to Be
Does Conda Replace the Need for Virtualenv
Scipy Curve_Fit Doesn't Like Math Module