Python 列表字典的笛卡尔积

Python 列表字典的笛卡尔积,python,generator,combinatorics,Python,Generator,Combinatorics,我试图写一些代码来测试一组输入参数的笛卡尔积 我看过itertools,但它的产品功能并不是我想要的。有没有一种简单而明显的方法来获取一个具有任意数量的键和每个值中任意数量的元素的字典,然后生成一个具有下一个排列的字典 输入: options = {"number": [1,2,3], "color": ["orange","blue"] } print list( my_product(options) ) 示例输出: [ {"number": 1, "color": "orange"},

我试图写一些代码来测试一组输入参数的笛卡尔积

我看过
itertools
,但它的
产品
功能并不是我想要的。有没有一种简单而明显的方法来获取一个具有任意数量的键和每个值中任意数量的元素的字典,然后生成一个具有下一个排列的字典

输入:

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"}
]

顺便说一下,这不是一个排列。排列是对列表的重新排列。这是列表中可能选择的枚举

编辑:在记住它被称为笛卡尔积之后,我想到了这个:

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]

好的,谢谢@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
。另外,我认为编写生成器函数,而不是返回生成器表达式的函数,可以使代码更清晰。因此:

def product_dict(**kwargs):
    keys = kwargs.keys()
    vals = kwargs.values()
    for instance in itertools.product(*vals):
        yield dict(zip(keys, instance))
如果您需要传入dict,
列表(product_dict(**mydict))
。使用
kwargs
而不是使用任意输入类的一个显著变化是,至少在Python 3.6之前,它可以防止对键/值进行排序

# I would like to do
keys,values = options.keys(), options.values()
# but I am not sure that the keys and values would always
# be returned in the same relative order. Comments?
keys = []
values = []
for k,v in options.iteritems():
    keys.append(k)
    values.append(v)

import itertools
opts = [dict(zip(keys,items)) for items in itertools.product(*values)]
导致

opts = [
    {'color': 'orange', 'number': 1},
    {'color': 'orange', 'number': 2},
    {'color': 'orange', 'number': 3},
    {'color': 'blue', 'number': 1},
    {'color': 'blue', 'number': 2},
    {'color': 'blue', 'number': 3}
]
Python3版本的


我很确定您不需要任何库来完成这项工作,但我对Python的了解还不足以回答这个问题。我猜列表理解就是诀窍。我想问的是,是否存在一个现成的生成器,可以很容易地进行调整来完成类似的工作。列表理解根本不相关。我试图解释为什么查找“排列”没有帮助。我记得这实际上是什么:它是笛卡尔积。首先,我要看一下itertools.product()。是的,完成了,谢谢你的指针。不过,欢迎使用堆栈溢出:答案应该是实际提供问题答案的答案。这是对这个问题的评论。@user470379不完全是,原始版本没有说明笛卡尔产品。除了我自己的答案之外,我似乎还不能对任何东西发表评论。如果可以的话,我会把它放在那里的。我很高兴我的回答让你找到了答案。啊,明白了。好的,再次感谢您帮助我走上正轨。我认为Python保证键()和值()及其对应的iter*将以相同的顺序返回。看@Seth:太好了!谢谢你,这已经困扰了我一段时间了。不客气。它非常方便,尤其是在这种情况下。如果你回顾我的答案,你会发现iterkeys/itervalues方法也可以避免创建大量临时表。字典条目无序存储的事实是否会影响这一点?这是一个非常简洁的代码,可以为Python 3用户快速生成单元测试用例(交叉验证集样式!)。我有一个更新版本@Phani我会说这没关系,因为键和值,即使无序,仍然是彼此一致的顺序。@Phani如果你使用这个字典列表作为
**kwargs
的列表,通过
映射
发送到函数,那么它类似于许多嵌套for循环。不同之处在于,您无法保证哪个循环在外部,哪个循环在内部。为了清晰起见,可以在左侧添加一个
.keys()
(dict(zip(dicts.keys(),x))
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()))