字典中列表的笛卡尔积
我正在尝试写一些代码,来测试一堆输入参数的笛卡尔积。
我看过 itertools
,但是它的 product
函数并不是我想要的。有没有一种简单明了的方法,可以从一个包含任意数量键的字典中,和每个值中有任意数量的元素,然后生成一个包含下一个排列的字典呢?
输入:
options = {"number": [1,2,3], "color": ["orange","blue"] }
print list( my_product(options) )
示例输出:
[ {"number": 1, "color": "orange"},
{"number": 1, "color": "blue"},
{"number": 2, "color": "orange"},
{"number": 2, "color": "blue"},
{"number": 3, "color": "orange"},
{"number": 3, "color": "blue"}
]
4 个回答
8
顺便说一下,这个不是排列。排列是指对一个列表的重新排列。而这里说的是从列表中可能选择的组合。
补充一下:我想起来这个叫做笛卡尔积,所以我想到了这个:
import itertools
options = {"number": [1,2,3], "color": ["orange","blue"] }
product = [x for x in apply(itertools.product, options.values())]
print([dict(zip(options.keys(), p)) for p in product])
39
这是Seth在StackOverflow上给出的答案的Python 3版本。
import itertools
def dict_product(dicts):
"""
>>> list(dict_product(dict(number=[1,2], character='ab')))
[{'character': 'a', 'number': 1},
{'character': 'a', 'number': 2},
{'character': 'b', 'number': 1},
{'character': 'b', 'number': 2}]
"""
return (dict(zip(dicts, x)) for x in itertools.product(*dicts.values()))
98
好的,感谢 @dfan 告诉我我在错误的地方寻找。我现在明白了:
from itertools import product
def my_product(inp):
return (dict(zip(inp.keys(), values)) for values in product(*inp.values())
编辑:经过多年的 Python 经验,我觉得一个更好的解决方案是接受 kwargs
,而不是输入一个字典;这样调用的方式更像是原始的 itertools.product
。另外,我觉得写一个生成器函数,而不是返回生成器表达式的函数,会让代码更清晰。所以:
import itertools
def product_dict(**kwargs):
keys = kwargs.keys()
for instance in itertools.product(*kwargs.values()):
yield dict(zip(keys, instance))
如果你需要传入一个字典,可以用 list(product_dict(**mydict))
。使用 kwargs
而不是任意输入类的一个显著变化是,它会阻止键/值的顺序,至少在 Python 3.6 之前是这样的。