Alle Kombinationen einer Liste von Listen


240

Ich suche im Grunde nach einer Python-Version von Combination ofList<List<int>>

Bei einer Liste von Listen benötige ich eine neue Liste, die alle möglichen Kombinationen von Elementen zwischen den Listen enthält.

[[1,2,3],[4,5,6],[7,8,9,10]] -> [[1,4,7],[1,4,8],...,[3,6,10]]

Die Anzahl der Listen ist unbekannt, daher brauche ich etwas, das in allen Fällen funktioniert. Bonuspunkte für Eleganz!

Antworten:


428

Sie brauchen itertools.product:

>>> import itertools
>>> a = [[1,2,3],[4,5,6],[7,8,9,10]]
>>> list(itertools.product(*a))
[(1, 4, 7), (1, 4, 8), (1, 4, 9), (1, 4, 10), (1, 5, 7), (1, 5, 8), (1, 5, 9), (1, 5, 10), (1, 6, 7), (1, 6, 8), (1, 6, 9), (1, 6, 10), (2, 4, 7), (2, 4, 8), (2, 4, 9), (2, 4, 10), (2, 5, 7), (2, 5, 8), (2, 5, 9), (2, 5, 10), (2, 6, 7), (2, 6, 8), (2, 6, 9), (2, 6, 10), (3, 4, 7), (3, 4, 8), (3, 4, 9), (3, 4, 10), (3, 5, 7), (3, 5, 8), (3, 5, 9), (3, 5, 10), (3, 6, 7), (3, 6, 8), (3, 6, 9), (3, 6, 10)]

20
Könnte jemand die Bedeutung des Sterns in erklären *a?
Serrano

52
*abedeutet, dass dies Argumente sind, die an die Funktion oder Methode übergeben werden. def fn(a,b,c):würde auf fn(*[1,2,3]) Referenz
mjallday

1
@mjallday, wäre es möglich, auch diese Kombinationen hinzuzufügen: (7,4,1), (8,4,1), (9,4,1), (10,4,1), (7,5, 1), (8,5,1), (9,5,1), (10,5,1) usw.
Reman

1
@Reman Es ist nicht ganz klar, was Sie erhalten möchten, aber wenn es sich zum Beispiel auch um die Umkehrung jedes Tupels handelt, können Sie eine Wrapper-Funktion verwenden, die aals Eingabe verwendet wird itertools.product(*a)und yieldsowohl das von erzeugte Tupel itertoolsals auch eine umgekehrte Version durchläuft. zB eine Liste erstellen, reverse()und wieder in Tupel konvertieren). Am besten eine neue Frage stellen.
Joachim Wagner

24

Die eleganteste Lösung ist die Verwendung von itertools.product in Python 2.6.

Wenn Sie Python 2.6 nicht verwenden, zeigen die Dokumente für itertools.product tatsächlich eine äquivalente Funktion, um das Produkt "manuell" auszuführen:

def product(*args, **kwds):
    # product('ABCD', 'xy') --> Ax Ay Bx By Cx Cy Dx Dy
    # product(range(2), repeat=3) --> 000 001 010 011 100 101 110 111
    pools = map(tuple, args) * kwds.get('repeat', 1)
    result = [[]]
    for pool in pools:
        result = [x+[y] for x in result for y in pool]
    for prod in result:
        yield tuple(prod)

19
listOLists = [[1,2,3],[4,5,6],[7,8,9,10]]
for list in itertools.product(*listOLists):
  print list;

Ich hoffe, Sie finden das genauso elegant wie bei meiner ersten Begegnung.


5
Was ist mit diesem Semikolon los? :)
Paolo Bergantino

3
Kraft der Gewohnheit. Ich finde es toll, wie Sie mit Python ein Semikolon einfügen können, um uns alten C / Java-Programmierern zu helfen. Aber es ist klar; ist nicht wirklich ein Anweisungsabschluss, wenn Sie so etwas wie print ("foo") machen ;; Das ist in C oder Java völlig legal (wenn auch sinnlos), aber in Python verboten.
Matthew Flaschen

5

Numpy kann es schaffen:

 >>> import numpy
 >>> a = [[1,2,3],[4,5,6],[7,8,9,10]]
 >>> [list(x) for x in numpy.array(numpy.meshgrid(*a)).T.reshape(-1,len(a))]
[[ 1, 4, 7], [1, 5, 7], [1, 6, 7], ....]

Könnte jemand das erklären?
Ashishv

5

An der direkten Rekursion für diese Aufgabe ist nichts auszusetzen. Wenn Sie eine Version benötigen, die mit Zeichenfolgen funktioniert, entspricht dies möglicherweise Ihren Anforderungen:

combinations = []

def combine(terms, accum):
    last = (len(terms) == 1)
    n = len(terms[0])
    for i in range(n):
        item = accum + terms[0][i]
        if last:
            combinations.append(item)
        else:
            combine(terms[1:], item)


>>> a = [['ab','cd','ef'],['12','34','56']]
>>> combine(a, '')
>>> print(combinations)
['ab12', 'ab34', 'ab56', 'cd12', 'cd34', 'cd56', 'ef12', 'ef34', 'ef56']

3

Hierfür kann man Base Python verwenden. Der Code benötigt eine Funktion zum Reduzieren von Listen von Listen:

def flatten(B):    # function needed for code below;
    A = []
    for i in B:
        if type(i) == list: A.extend(i)
        else: A.append(i)
    return A

Dann kann man laufen:

L = [[1,2,3],[4,5,6],[7,8,9,10]]

outlist =[]; templist =[[]]
for sublist in L:
    outlist = templist; templist = [[]]
    for sitem in sublist:
        for oitem in outlist:
            newitem = [oitem]
            if newitem == [[]]: newitem = [sitem]
            else: newitem = [newitem[0], sitem]
            templist.append(flatten(newitem))

outlist = list(filter(lambda x: len(x)==len(L), templist))  # remove some partial lists that also creep in;
print(outlist)

Ausgabe:

[[1, 4, 7], [2, 4, 7], [3, 4, 7], 
[1, 5, 7], [2, 5, 7], [3, 5, 7], 
[1, 6, 7], [2, 6, 7], [3, 6, 7], 
[1, 4, 8], [2, 4, 8], [3, 4, 8], 
[1, 5, 8], [2, 5, 8], [3, 5, 8], 
[1, 6, 8], [2, 6, 8], [3, 6, 8], 
[1, 4, 9], [2, 4, 9], [3, 4, 9], 
[1, 5, 9], [2, 5, 9], [3, 5, 9], 
[1, 6, 9], [2, 6, 9], [3, 6, 9], 
[1, 4, 10], [2, 4, 10], [3, 4, 10], 
[1, 5, 10], [2, 5, 10], [3, 5, 10], 
[1, 6, 10], [2, 6, 10], [3, 6, 10]]

-1
from itertools import product 
list_vals = [['Brand Acronym:CBIQ', 'Brand Acronym :KMEFIC'],['Brand Country:DXB','Brand Country:BH']]
list(product(*list_vals))

Ausgabe:

[('Markenakronym: CBIQ', 'Markenland: DXB'),
('Markenakronym: CBIQ', 'Markenland: BH'),
('Markenakronym: KMEFIC', 'Markenland: DXB'),
( 'Markenakronym: KMEFIC', 'Markenland: BH')]


Diese Antwort sollte akzeptiert werden, da sie als einzige eine integrierte Funktion verwendet und gleichzeitig hervorhebt, dass sie auch für alle und auch heterogene Typen funktioniert.
Pedjjj

Wie unterscheidet sich diese Antwort von der vor vielen Jahren?
Dawid Laszuk
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.