Kombinationen zwischen zwei Listen?

184

Es ist eine Weile her und ich habe Probleme, meinen Kopf um einen Algorithmus zu wickeln, den ich zu machen versuche. Grundsätzlich habe ich zwei Listen und möchte alle Kombinationen der beiden Listen erhalten.

Ich erkläre es möglicherweise nicht richtig, daher hier ein Beispiel.

name = 'a', 'b'
number = 1, 2

Die Ausgabe in diesem Fall wäre:

1.  A1 B2
2.  B1 A2

Der schwierige Teil ist, dass ich möglicherweise mehr Elemente in der Variablen "name" als Elemente in der Variablen "number" habe (number ist immer gleich oder kleiner als die Variable name).

Ich bin verwirrt darüber, wie alle Kombinationen ausgeführt werden sollen (verschachtelt für Schleife?) Und noch verwirrter über die Logik, die Elemente in der Namensvariablen zu verschieben, falls mehr Elemente im Namen enthalten sind als in der Nummernliste.

Ich bin nicht der beste Programmierer, aber ich denke, ich kann es versuchen, wenn mir jemand helfen kann, die Logik / den Algorithmus zu klären, um dies zu erreichen. Also bin ich gerade auf verschachtelten Schleifen festgefahren.

Aktualisieren:

Hier ist die Ausgabe mit 3 Variablen und 2 Zahlen:

name = 'a', 'b', 'c'
number = 1, 2

Ausgabe:

1.  A1 B2
2.  B1 A2
3.  A1 C2
4.  C1 A2
5.  B1 C2
6.  C1 B2
user1735075
quelle
1
@ dm03514 Ich habe das gesehen und Beispiele für ähnliche Ziele mit itertools gefunden, aber ich arbeite als Prototyp in Python, schreibe aber den endgültigen Code in einer anderen Sprache, sodass ich keine Tools verwenden möchte, die ansonsten nicht verfügbar sind.
user1735075
1
Was Sie verlangen, macht nicht wirklich Sinn. Wenn die erste Liste A, B, C und die zweite 1,2 enthält, welches Ergebnis würden Sie erwarten? Dies wäre möglich, wenn das von Ihnen angegebene Beispiel 4 verschiedene Ergebnisse mit jeweils einem Buchstaben und einer Zahl (A1, A2, B1, B2) hätte oder wenn beide Listen dieselbe Größe haben müssten.
Interjay
1
Ich stimme Interjay zu. Bitte geben Sie das Ergebnis im Fall ungleicher Größe an, da sonst keine allgemeine Lösung möglich ist.
Bakuriu
Hallo allerseits, ich habe die Antwort aktualisiert, um die Ausgabe mit 3 Namen und 2 Zahlen anzuzeigen. Ich dachte, ich hätte es gut erklärt, nicht sicher, warum die Abstimmung.
user1735075

Antworten:

92

Hinweis : Diese Antwort bezieht sich auf die oben gestellte Frage. Wenn Sie von Google hier sind und nur nach einer Möglichkeit suchen, ein kartesisches Produkt in Python zu erhalten, itertools.productoder wenn Sie nach einem einfachen Listenverständnis suchen, lesen Sie die anderen Antworten.


Angenommen, wir nehmen an len(list1) >= len(list2). Dann scheinen Sie zu wollen, alle Permutationen der Länge len(list2)von zu nehmen list1und sie mit Elementen aus Liste2 abzugleichen. In Python:

import itertools
list1=['a','b','c']
list2=[1,2]

[list(zip(x,list2)) for x in itertools.permutations(list1,len(list2))]

Kehrt zurück

[[('a', 1), ('b', 2)], [('a', 1), ('c', 2)], [('b', 1), ('a', 2)], [('b', 1), ('c', 2)], [('c', 1), ('a', 2)], [('c', 1), ('b', 2)]]
Interjay
quelle
1
Das Ergebnis ist genau das, was ich will, aber ist es möglich, die Logik dahinter zu teilen, wie es geht? Wenn ich meinen Code in C oder Java konvertiere, habe ich keinen Zugriff auf zip oder itertools (obwohl sie das Leben sehr, sehr einfach machen)
user1735075
3
@ user1735075 Schauen Sie sich die Dokumentation an
Faultier
1
@ user1735075: Weißt du, dass Python Open Source ist? Sie können also einfach die Quellen herunterladen und sehen, was sie tun. +1 an Mr. Steak für den Hinweis, dass die Dokumentation tatsächlich eine Beispielimplementierung enthält, die nicht verwendet wird zipund ähnlich ist.
Bakuriu
2
Ich kann das buchstäblich nicht zum Laufen bringen, selbst mit Ihrem Beispiel ... alles was ich bekomme ist eine Liste von Zip-Objekten ..: |
m1nkeh
1
@logic bietet die akzeptierte Lösung.
Bernhard Wagner
497

Der einfachste Weg ist zu verwenden itertools.product:

a = ["foo", "melon"]
b = [True, False]
c = list(itertools.product(a, b))
>> [("foo", True), ("foo", False), ("melon", True), ("melon", False)]
DrIDK
quelle
10
OP hat nicht nach einem kartesischen Produkt gefragt, und diese Antwort (wie auch die meisten anderen) liefert nicht das erwartete Ergebnis, das in der Frage angegeben ist.
Interjay
17
@interjay Sie haben sehr Recht, aber da zu viele Leute diese Antwort als richtig zu finden scheinen, kann ich nur annehmen, dass der Titel der Frage keinen Kontext hat.
xpy
3
@xpy Der Titel ist zu kurz, um alles zu erklären. Deshalb müssen Sie die eigentliche Frage lesen.
Interjay
10
OP wollte Permuationen, aber Google schickt jeden, der nach Kombinationen sucht (wie ich), zu dieser Antwort - froh zu sehen, dass sie das 8-fache der Stimmen hat!
Josh Friedlander
158

Kann einfacher sein als die einfachste oben:

>>> a = ["foo", "bar"]
>>> b = [1, 2, 3]
>>> [(x,y) for x in a for y in b]  # for a list
[('foo', 1), ('foo', 2), ('foo', 3), ('bar', 1), ('bar', 2), ('bar', 3)]
>>> ((x,y) for x in a for y in b)  # for a generator if you worry about memory or time complexity.
<generator object <genexpr> at 0x1048de850>

ohne Import

Logik
quelle
Beste Lösung! Danke dir! Andere Lösungen sind entweder einfach falsch oder funktionieren nur in bestimmten Fällen wie a> b usw.
Philipp Schwarz
3
Die pythonischste Lösung! (und vermeidet unnötige Importe)
Dalker
6
Zeitkomplexität ist O (n ^ 2)
Deepak Sharma
2
Wetten Lösung !!
Nackte
22

Ich suchte nach einer Liste, die mit nur eindeutigen Kombinationen multipliziert wurde und als diese Funktion bereitgestellt wird.

import itertools
itertools.combinations(list, n_times)

Hier als Auszug aus den Python-Dokumenten zu itertools Das könnte Ihnen helfen, das zu finden, wonach Sie suchen.

Combinatoric generators:

Iterator                                 | Results
-----------------------------------------+----------------------------------------
product(p, q, ... [repeat=1])            | cartesian product, equivalent to a 
                                         |   nested for-loop
-----------------------------------------+----------------------------------------
permutations(p[, r])                     | r-length tuples, all possible 
                                         |   orderings, no repeated elements
-----------------------------------------+----------------------------------------
combinations(p, r)                       | r-length tuples, in sorted order, no 
                                         |   repeated elements
-----------------------------------------+----------------------------------------
combinations_with_replacement(p, r)      | r-length tuples, in sorted order, 
                                         | with repeated elements
-----------------------------------------+----------------------------------------
product('ABCD', repeat=2)                | AA AB AC AD BA BB BC BD CA CB CC CD DA DB DC DD
permutations('ABCD', 2)                  | AB AC AD BA BC BD CA CB CD DA DB DC
combinations('ABCD', 2)                  | AB AC AD BC BD CD
combinations_with_replacement('ABCD', 2) | AA AB AC AD BB BC BD CC CD DD
ThorSummoner
quelle
11

Vielleicht möchten Sie ein einzeiliges Listenverständnis ausprobieren:

>>> [name+number for name in 'ab' for number in '12']
['a1', 'a2', 'b1', 'b2']
>>> [name+number for name in 'abc' for number in '12']
['a1', 'a2', 'b1', 'b2', 'c1', 'c2']
Idanmel
quelle
10

Der beste Weg, um alle Kombinationen für eine große Anzahl von Listen herauszufinden, ist:

import itertools
from pprint import pprint

inputdata = [
    ['a', 'b', 'c'],
    ['d'],
    ['e', 'f'],
]
result = list(itertools.product(*inputdata))
pprint(result)

Das Ergebnis wird sein:

[('a', 'd', 'e'),
 ('a', 'd', 'f'),
 ('b', 'd', 'e'),
 ('b', 'd', 'f'),
 ('c', 'd', 'e'),
 ('c', 'd', 'f')]
Ishan Rastogi
quelle
Danke, tolle Antwort!
Toinbis
10

Oder die KISS-Antwort für kurze Listen:

[(i, j) for i in list1 for j in list2]

Nicht so performant wie itertools, aber Sie verwenden Python, sodass Leistung bereits nicht Ihr Hauptanliegen ist ...

Ich mag auch alle anderen Antworten!

Fletch F Fletch
quelle
8

Eine winzige Verbesserung für die Antwort von Interjay, um das Ergebnis als Abflachungsliste zu erstellen.

>>> list3 = [zip(x,list2) for x in itertools.permutations(list1,len(list2))]
>>> import itertools
>>> chain = itertools.chain(*list3)
>>> list4 = list(chain)
[('a', 1), ('b', 2), ('a', 1), ('c', 2), ('b', 1), ('a', 2), ('b', 1), ('c', 2), ('c', 1), ('a', 2), ('c', 1), ('b', 2)]

Referenz von diesem Link

Masse Zhou
quelle
4

Ohne itertools

[(list1[i], list2[j]) for i in xrange(len(list1)) for j in xrange(len(list2))]
user3684792
quelle
4

Beantworten Sie die Frage "Bei zwei Listen finden Sie alle möglichen Permutationen von Paaren eines Elements aus jeder Liste" und verwenden Sie die grundlegende Python-Funktionalität (dh ohne itertools), um die Replikation für andere Programmiersprachen zu vereinfachen:

def rec(a, b, ll, size):
    ret = []
    for i,e in enumerate(a):
        for j,f in enumerate(b):
            l = [e+f]
            new_l = rec(a[i+1:], b[:j]+b[j+1:], ll, size)
            if not new_l:
                ret.append(l)
            for k in new_l:
                l_k = l + k
                ret.append(l_k)
                if len(l_k) == size:
                    ll.append(l_k)
    return ret

a = ['a','b','c']
b = ['1','2']
ll = []
rec(a,b,ll, min(len(a),len(b)))
print(ll)

Kehrt zurück

[['a1', 'b2'], ['a1', 'c2'], ['a2', 'b1'], ['a2', 'c1'], ['b1', 'c2'], ['b2', 'c1']]
Computerist
quelle
2

Die besseren Antworten darauf funktionieren nur für bestimmte Längen von Listen, die bereitgestellt werden.

Hier ist eine Version, die für jede Länge von Eingaben funktioniert. Es macht den Algorithmus auch in Bezug auf die mathematischen Konzepte der Kombination und Permutation klar.

from itertools import combinations, permutations
list1 = ['1', '2']
list2 = ['A', 'B', 'C']

num_elements = min(len(list1), len(list2))
list1_combs = list(combinations(list1, num_elements))
list2_perms = list(permutations(list2, num_elements))
result = [
  tuple(zip(perm, comb))
  for comb in list1_combs
  for perm in list2_perms
]

for idx, ((l11, l12), (l21, l22)) in enumerate(result):
  print(f'{idx}: {l11}{l12} {l21}{l22}')

Dies gibt aus:

0: A1 B2
1: A1 C2
2: B1 A2
3: B1 C2
4: C1 A2
5: C1 B2
Steve Alexander
quelle