2011-03-08 127 views
30

我试图编写一些代码来测试一堆输入参数的笛卡尔乘积。列表字典的笛卡尔积

我看过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"} 
] 
+0

我敢肯定,你不需要任何库来做到这一点,但我不知道Python足够好地回答。我猜想列表理解是个诀窍。 – 2011-03-08 04:00:31

+0

我在问是否有现成的发电机,可以很容易地适应做这样的事情。列表理解并不重要。 – 2011-03-08 04:02:08

回答

29

好,感谢@dfan告诉我,我一直在寻找在错误的地方。我想起来了:

def my_product(dicts): 
    return (dict(izip(dicts, x)) for x in product(*dicts.itervalues())) 
+2

字典条目无序存储的事实是否影响到这一点? – Phani 2014-06-20 20:50:46

+1

这是一个非常整洁的代码,用于快速生成单元测试用例(交叉验证集样式!) – gaborous 2015-07-07 14:04:20

+0

适用于Python 3用户。我有一个更新的版本[这里](http://stackoverflow.com/a/40623158/621449) – Tarrasch 2016-11-16 02:37:01

5

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

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

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] 
+0

我试图解释为什么查找“排列组合”没有帮助。我记得这实际上是什么:这是一个笛卡儿的产品。我会先看itertools.product()。 – dfan 2011-03-08 04:09:51

+0

是的,完成,并感谢指针。但是,仍然欢迎Stack Overflow:答案应该是实际提供问题答案的答案。这属于对这个问题的评论。 – 2011-03-08 04:13:31

+0

@ user470379不是真的,原始版本没有说明笛卡尔积 – 2011-03-08 04:14:15

2
# 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} 
] 
+2

我认为Python保证keys()和values()及其相应的iter *将以相同的顺序返回。见http://docs.python.org/library/stdtypes.html#dict.items – 2011-03-08 04:21:17

+0

@Seth:太棒了!谢谢,这一直困扰我一段时间。 – 2011-03-08 15:43:04

+0

你很受欢迎。这非常方便,特别是对于这种情况。如果您查看我的答案,可以看到iterkeys/itervalues方法也可以帮助您避免创建一堆临时对象。 – 2011-03-08 15:50:32

9

的Python 3 Seth's answer版本。

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()))