2012-10-09 12 views
11

Mam listę list i ciąg separatora takiego:Get dołączył ciąg z listy list ciągi w Pythonie

lists = [ 
    ['a', 'b'], 
    [1, 2], 
    ['i', 'ii'], 
] 
separator = '-' 

W wyniku Chcę mieć listę łańcuchów połączonych z separatorem ciąg od ciągi w pod-listach:

result = [ 
    'a-1-i', 
    'a-1-ii', 
    'a-2-i', 
    'a-2-ii', 
    'b-1-i', 
    'b-1-ii', 
    'b-2-i', 
    'b-2-ii', 
] 

Zamówienie w wyniku nie ma znaczenia.

Jak mogę to zrobić?

+0

w tej chwili nie jestem pewien, w jaki sposób uzyskać tej pracy w miłej pythonic sposób i nie jest to praca domowa;) – Martin

Odpowiedz

16
from itertools import product 
result = [separator.join(map(str,x)) for x in product(*lists)] 

itertools.product zwraca iterator, który produkuje iloczyn kartezjański świadczonych iterables. Musimy uzyskać mapstr nad wynikowymi krotkami, ponieważ niektóre z nich to ints. Wreszcie możemy dołączyć do usztywnionych krotek i rzucić całą rzecz w zrozumienie listy (lub wyrażenie generatora, jeśli mamy do czynienia z dużym zbiorem danych, i po prostu potrzebujesz go do iteracji).

+1

+1 Świetna odpowiedź człowiek - chcę to wydrukować i umieścić na mojej lodówce. – RocketDonkey

3
>>> from itertools import product 
>>> result = list(product(*lists)) 
>>> result = [separator.join(map(str, r)) for r in result] 
>>> result 
['a-1-i', 'a-1-ii', 'a-2-i', 'a-2-ii', 'b-1-i', 'b-1-ii', 'b-2-i', 'b-2-ii'] 

Jak @jpm wskazał, naprawdę nie trzeba rzucać list do generatora product. Miałem je, aby zobaczyć wyniki w mojej konsoli, ale nie są one naprawdę potrzebne tutaj.

+0

Nie trzeba zmuszać produktu do konstruktora 'list'. 'map' działa dobrze na iteratorze. Ponadto nie trzeba wymuszać na tym liście krotek z tego iteratora. 'map' i' join' działają dobrze na krotkach. – jpm

+0

@jpm tak, wciąż to edytowałem. Początkowo miałem je podczas próby w mojej konsoli, aby zobaczyć wyniki, powinienem je później usunąć :) –

+1

Kolejny punkt na zmuszeniu iteratora do pośredniej listy: jeśli produkt kartezjański staje się duży (całkowicie możliwy scenariusz, pomimo tego, co pokazuje ten przykład), prawdopodobnie chcemy opóźnić umieszczenie wszystkiego w pamięci tak długo, jak to możliwe. W zależności od aplikacji możemy nawet chcieć użyć wyrażenia generatora zamiast rozumienia listy. – jpm

1
["%s%c%s%c%s" % (a, separator, b, separator, c) for a in lists[0] for b in lists[1] for c in lists[2]] 
3

Można to zrobić za pomocą poleceń wbudowanych:

>>> map(separator.join, reduce(lambda c,n: [a+[str(b)] for b in n for a in c], lists, [[]])) 
['a-1-i', 'b-1-i', 'a-2-i', 'b-2-i', 'a-1-ii', 'b-1-ii', 'a-2-ii', 'b-2-ii'] 
+0

Przyjemne wykorzystanie technik funkcjonalnych. Jeśli zamienisz klauzule "za" na zrozumienie, możesz nawet dopasować dane wyjściowe żądane przez OP. – jpm

+0

Co ciekawe, to rozwiązanie jest nieco wolniejsze niż moje (niecałe 2 sekundy ponad 2 000 000 powtórzeń, za pośrednictwem timeit). Nie trzeba się martwić o prawie każdą aplikację, ale uznałem to za interesujące. – jpm

+0

Dzięki. Nie zastanawiałem się zbytnio nad kolejnością terminów, ale PO powiedział, że nie dba o zamówienie. – Benedict