2011-03-08 131 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()))