Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cartesian product of a dictionary of lists

I'm trying to write some code to test out the Cartesian product of a bunch of input parameters.

I've looked at itertools, but its product function is not exactly what I want. Is there a simple obvious way to take a dictionary with an arbitrary number of keys and an arbitrary number of elements in each value, and then yield a dictionary with the next permutation?

Input:

options = {"number": [1,2,3], "color": ["orange","blue"] } print list( my_product(options) ) 

Example output:

[ {"number": 1, "color": "orange"},   {"number": 1, "color": "blue"},   {"number": 2, "color": "orange"},   {"number": 2, "color": "blue"},   {"number": 3, "color": "orange"},   {"number": 3, "color": "blue"} ] 
like image 750
Seth Johnson Avatar asked Mar 08 '11 03:03

Seth Johnson


People also ask

How do you find the Cartesian product for a list set?

The Cartesian square of a set X is the Cartesian product X2 = X × X. An example is the 2-dimensional plane R2 = R × R where R is the set of real numbers: R2 is the set of all points (x,y) where x and y are real numbers (see the Cartesian coordinate system).

Can lists be dictionary values?

It definitely can have a list and any object as value but the dictionary cannot have a list as key because the list is mutable data structure and keys cannot be mutable else of what use are they.

Which function returns a list of dictionary?

Method 1: Get dictionary keys as a list using dict. The dict. keys() method in Python Dictionary, returns a view object that displays a list of all the keys in the dictionary in order of insertion.


1 Answers

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.

like image 53
Seth Johnson Avatar answered Sep 21 '22 08:09

Seth Johnson