2011-03-08 29 views
30

Bir dizi giriş parametresinin Kartezyen ürününü test etmek için bir miktar kod yazmaya çalışıyorum.Listelerin bir sözlüğünün kartezyen çarpımı

itertools'a baktım ama product işlevi tam olarak istediğim gibi değil. ve anahtarlarının rasgele sayıları ile her bir değerin rasgele sayıdaki bir öğeyi içeren bir sözlük almak ve sonra bir sonraki permütasyona sahip bir sözlük vermek için basit bir açık yol var mı?

Girdi:

options = {"number": [1,2,3], "color": ["orange","blue"] } 
print list(my_product(options)) 

Örnek çıktı: Bu arada

[ {"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

Bunu yapmak için herhangi bir kütüphane gerekmez eminim, ama ben oldukça yeterince iyi cevap Python bilmiyorum. Listedeki anlamaların hile olduğunu tahmin ediyorum. –

+0

Böyle bir şey yapmak için kolayca uyarlanabilen hazır bir jeneratör olup olmadığını soruyorum. Anlama listelerinin hepsi alakalı değildir. –

cevap

29

Tamam, teşekkürler ben yanlış yerde arıyordu söylediğin için @dfan için. Bunu şimdi var:

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

Sözlük girişlerinin sırasız olarak saklanması gerçeği bu durumu etkiliyor mu? – Phani

+1

Bu, hızlı bir şekilde birim sınama durumları oluşturmak için çok temiz bir koddur (çapraz doğrulama set stili!) – gaborous

+0

Python 3 kullanıcıları için. Güncellenmiş bir sürümüm var [burada] (http://stackoverflow.com/a/40623158/621449) – Tarrasch

5

, bu bir permütasyon değildir. Bir permütasyon bir listenin yeniden düzenlenmesidir. Bu listelerden olası seçimlerin bir numaralandırmasıdır.

Düzenleme: Kartezyen ürün olarak adlandırılan olduğunu hatırlayarak sonra ben bu geldi:

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

Neden "permütasyonlar" aradığına yardım etmeye çalışmıyordum. Bunun gerçekte ne olduğunu hatırladım: Kartezyen bir üründür. Itertools.product() 'a bakarak başlayacağım. – dfan

+0

Evet, tamam ve işaretçi için teşekkürler. Ama yine de, Stack Overflow'a hoş geldiniz: bir cevap, soruyu gerçekten cevaplayan bir cevap olmalıdır. Bu soruya bir yorum olarak ait. –

+0

@ user470379 gerçekte, orijinal versiyonu Cartesian ürününü göstermedi –

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

sonuçları

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

Sanırım Python, keys() ve values ​​() ile bunlara karşılık gelen iter * 'in aynı sırayla döndüğünü garanti eder. Bkz. Http://docs.python.org/library/stdtypes.html#dict.items –

+0

@Seth: Mükemmel! Teşekkürler, bu beni bir süredir rahatsız ediyordu. –

+0

oldukça hoş geldiniz. Çok kullanışlı ve özellikle bu dava için. Cevabımı incelerseniz, iterkeys/itervalues ​​yöntemlerinin sizi bir grup zamansal oluşturmadan da kurtaracağını görebilirsiniz. –

9

yılında Python 3 Seth's answer sürümünü.

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