字典中列表的笛卡尔积

91 投票
4 回答
30107 浏览
提问于 2025-04-16 13:13

我正在尝试写一些代码,来测试一堆输入参数的笛卡尔积。

我看过 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 之前是这样的。

撰写回答