Operation für jedes Elementpaar in einer Liste

93

Mit Python möchte ich jedes mögliche Paar in einer Liste vergleichen.

Angenommen, ich habe

my_list = [1,2,3,4]

Ich möchte eine Operation (nennen wir es foo) für jede Kombination von 2 Elementen aus der Liste ausführen.

Das Endergebnis sollte das gleiche sein wie

foo(1,1)
foo(1,2)
...
foo(4,3)
foo(4,4)

Mein erster Gedanke war, die Liste zweimal manuell zu durchlaufen, aber das scheint nicht sehr pythonisch zu sein.

GuiSim
quelle

Antworten:

228

Check out product()im itertoolsModul. Es macht genau das, was Sie beschreiben.

import itertools

my_list = [1,2,3,4]
for pair in itertools.product(my_list, repeat=2):
    foo(*pair)

Dies entspricht:

my_list = [1,2,3,4]
for x in my_list:
    for y in my_list:
        foo(x, y)

Bearbeiten: Es gibt auch zwei sehr ähnliche Funktionen, permutations()und combinations(). Um zu veranschaulichen, wie sie sich unterscheiden:

product() generiert jede mögliche Paarung von Elementen, einschließlich aller Duplikate:

1,1  1,2  1,3  1,4
2,1  2,2  2,3  2,4
3,1  3,2  3,3  3,4
4,1  4,2  4,3  4,4

permutations()generiert alle eindeutigen Ordnungen jedes eindeutigen Elementpaars, wobei die x,xDuplikate entfernt werden:

 .   1,2  1,3  1,4
2,1   .   2,3  2,4
3,1  3,2   .   3,4
4,1  4,2  4,3   .

Schließlich wird combinations()nur jedes einzelne Elementpaar in lexikografischer Reihenfolge generiert:

 .   1,2  1,3  1,4
 .    .   2,3  2,4
 .    .    .   3,4
 .    .    .    .

Alle drei Funktionen wurden in Python 2.6 eingeführt.

Ben Blank
quelle
1
Seltsam, wenn ich itertools.product (my_list, 2) ausführe, wird beschwert, dass int nicht aufrufbar ist. Funktioniert, wenn ich es ändere in: itertools.product (my_list, repeat = 2)
ojrac
Beachten Sie, dass itertools.product () in Python 2.6 neu ist.
Mike Mazur
Nur für die Nachwelt möchte ich darauf hinweisen, dass itertools.combinations im ursprünglichen Beispiel nicht die Zeilen foo (1,1) oder foo (4,4) erzeugen würde.
Kylotan
2
Es gibt auch Kombinationen mit Ersatz (). Wie Kombinationen (), jedoch einschließlich der Diagonale (gemäß den Abbildungen).
Ziegl
1
Für die Faulen: Um die obigen Ergebnisse mit bekommen permutations()und combinations()Verwendung r=2anstelle der repeat=2für am Beispiel verwendetproduct()
Rob
15

Ich hatte ein ähnliches Problem und die Lösung gefunden hier . Es funktioniert, ohne dass ein Modul importiert werden muss.

Angenommen, eine Liste wie:

people = ["Lisa","Pam","Phil","John"]

Eine vereinfachte einzeilige Lösung würde so aussehen.

Alle möglichen Paare , einschließlich Duplikate:

result = [foo(p1, p2) for p1 in people for p2 in people]

Alle möglichen Paare, ausgenommen Duplikate :

result = [foo(p1, p2) for p1 in people for p2 in people if p1 != p2]

Einzigartige Paare , bei denen die Reihenfolge keine Rolle spielt:

result = [foo(people[p1], people[p2]) for p1 in range(len(people)) for p2 in range(p1+1,len(people))]

Für den Fall, dass Sie nicht operieren möchten, sondern nur die Paare erhalten foomöchten, reicht es aus , die Funktion zu entfernen und nur ein Tupel zu verwenden.

Alle möglichen Paare , einschließlich Duplikate:

list_of_pairs = [(p1, p2) for p1 in people for p2 in people]

Ergebnis:

('Lisa', 'Lisa')
('Lisa', 'Pam')
('Lisa', 'Phil')
('Lisa', 'John')
('Pam', 'Lisa')
('Pam', 'Pam')
('Pam', 'Phil')
('Pam', 'John')
('Phil', 'Lisa')
('Phil', 'Pam')
('Phil', 'Phil')
('Phil', 'John')
('John', 'Lisa')
('John', 'Pam')
('John', 'Phil')
('John', 'John')

Alle möglichen Paare, ausgenommen Duplikate :

list_of_pairs = [(p1, p2) for p1 in people for p2 in people if p1 != p2]

Ergebnis:

('Lisa', 'Pam')
('Lisa', 'Phil')
('Lisa', 'John')
('Pam', 'Lisa')
('Pam', 'Phil')
('Pam', 'John')
('Phil', 'Lisa')
('Phil', 'Pam')
('Phil', 'John')
('John', 'Lisa')
('John', 'Pam')
('John', 'Phil')

Einzigartige Paare , bei denen die Reihenfolge keine Rolle spielt:

list_of_pairs = [(people[p1], people[p2]) for p1 in range(len(people)) for p2 in range(p1+1,len(people))]

Ergebnis:

('Lisa', 'Pam')
('Lisa', 'Phil')
('Lisa', 'John')
('Pam', 'Phil')
('Pam', 'John')
('Phil', 'John')

Bearbeiten: Nach der Überarbeitung zur Vereinfachung dieser Lösung wurde mir klar, dass es der gleiche Ansatz ist wie Adam Rosenfield. Ich hoffe, die größere Erklärung hilft einigen, es besser zu verstehen.

J0ANMM
quelle
2
Ich ziehe es dem Import einer Bibliothek vor, viel sauberer!
Sudo-Nim
itertools ist Teil von Python. Es ist keine externe Bibliothek.
GuiSim
2

Wenn Sie nur eine Funktion aufrufen, können Sie nicht viel besser machen als:

for i in my_list:
    for j in my_list:
        foo(i, j)

Wenn Sie eine Liste der Ergebnisse des Aufrufs der Funktion erfassen möchten, haben Sie folgende Möglichkeiten:

[foo(i, j) for i in my_list for j in my_list]

Daraufhin erhalten Sie eine Liste der Ergebnisse der Anwendung foo(i, j)auf jedes mögliche Paar (i, j).

Adam Rosenfield
quelle
0
my_list = [1,2,3,4]

pairs=[[x,y] for x in my_list for y in my_list]
print (pairs)
Karan Dave
quelle
Obwohl dieser Code das Problem möglicherweise löst, erfordert eine gute Antwort auch eine Erklärung, was der Code tut und wie er das Problem löst.
BDL