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!

Lin
quelle

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)]
SilentGhost
quelle
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)
Jarret Hardie
quelle
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.

Matthew Flaschen
quelle
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], ....]
Diamantatos Paraskevas
quelle
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']
duanev
quelle
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]]
rnso
quelle
-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')]

Kez
quelle
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