简体   繁体   中英

Cartesian product of a dictionary of lists - with sorting

Background

I'm currently using a technique that is perfectly demonstrated in another Stackoverflow post to create the Cartesian product of a dictionary of lists, ie:

from itertools import product
def my_product(inp):
    return (dict(zip(inp.keys(), values)) for values in product(*inp.values())

Problem

Here's my sample dictionary, d :

d = {
    "letters": ['a', 'b'],
    "numbers": [1, 2, 3],
    "status": ["on", "off"]
}

The problem I'm running into, is that I want to use this technique to create a generator. However, I want to control the order in which certain lists are "swept". For example, here's a common result for the first few iterations generated by my code:

{"status": "on",  "numbers": 1, "letters": 'a'}
{"status": "off", "numbers": 1, "letters": 'a'}
{"status": "on",  "numbers": 2, "letters": 'a'}
{"status": "off", "numbers": 2, "letters": 'a'}
{"status": "on",  "numbers": 3, "letters": 'a'}
{"status": "off", "numbers": 3, "letters": 'a'}
{"status": "on",  "numbers": 1, "letters": 'b'}
{"status": "off", "numbers": 1, "letters": 'b'}

However, I need to be able to control the ordering of how the product generates these permutations. The code which is "fed" the dictionaries has a high "cost" when I toggle the "on"/"off" value of "status", but no penalty is incurred for changing the "numbers" or "letters" elements. For example, this would be the ideal set of iterations yielded by the generator:

{"letters": 'a', "numbers": 1, "status": "on"}
{"letters": 'a', "numbers": 2, "status": "on"}
{"letters": 'a', "numbers": 3, "status": "on"}
{"letters": 'b', "numbers": 1, "status": "on"}
{"letters": 'b', "numbers": 2, "status": "on"}
{"letters": 'b', "numbers": 3, "status": "on"}
{"letters": 'a', "numbers": 1, "status": "off"}
{"letters": 'a', "numbers": 2, "status": "off"}
{"letters": 'a', "numbers": 3, "status": "off"}
{"letters": 'b', "numbers": 1, "status": "off"}
{"letters": 'b', "numbers": 2, "status": "off"}
{"letters": 'b', "numbers": 3, "status": "off"}

In short, I want to be able to minimize the number of transitions from one value to another by showing "preference" to certain members of the dictionary, d .


Question

How can I accomplish this?


Conclusion

Using the accepted answer, I generated this code snippet:


Code Listing

#!/usr/bin/env python
from collections import OrderedDict
from itertools import product

d = OrderedDict()
d["status"] = ["on", "off"]
d["letters"] = ["a", "b", "c"]
d["numbers"] = [1, 2, 3, 4]

for i in (dict(zip(inp.keys(), values)) for values in product(*inp.values())):
    print(i)

Sample Output

{'status': 'on', 'letters': 'a', 'numbers': 1}
{'status': 'on', 'letters': 'a', 'numbers': 2}
{'status': 'on', 'letters': 'a', 'numbers': 3}
{'status': 'on', 'letters': 'a', 'numbers': 4}
{'status': 'on', 'letters': 'b', 'numbers': 1}
{'status': 'on', 'letters': 'b', 'numbers': 2}
{'status': 'on', 'letters': 'b', 'numbers': 3}
{'status': 'on', 'letters': 'b', 'numbers': 4}
{'status': 'on', 'letters': 'c', 'numbers': 1}
{'status': 'on', 'letters': 'c', 'numbers': 2}
{'status': 'on', 'letters': 'c', 'numbers': 3}
{'status': 'on', 'letters': 'c', 'numbers': 4}
{'status': 'off', 'letters': 'a', 'numbers': 1}
{'status': 'off', 'letters': 'a', 'numbers': 2}
{'status': 'off', 'letters': 'a', 'numbers': 3}
{'status': 'off', 'letters': 'a', 'numbers': 4}
{'status': 'off', 'letters': 'b', 'numbers': 1}
{'status': 'off', 'letters': 'b', 'numbers': 2}
{'status': 'off', 'letters': 'b', 'numbers': 3}
{'status': 'off', 'letters': 'b', 'numbers': 4}
{'status': 'off', 'letters': 'c', 'numbers': 1}
{'status': 'off', 'letters': 'c', 'numbers': 2}
{'status': 'off', 'letters': 'c', 'numbers': 3}
{'status': 'off', 'letters': 'c', 'numbers': 4}

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM