Operazione su ogni coppia di elementi in un elenco


94

Usando Python, vorrei confrontare ogni possibile coppia in un elenco.

Supponiamo di averlo fatto

my_list = [1,2,3,4]

Vorrei fare un'operazione (chiamiamola pippo) su ogni combinazione di 2 elementi della lista.

Il risultato finale dovrebbe essere lo stesso di

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

Il mio primo pensiero è stato quello di scorrere due volte l'elenco manualmente, ma non sembra molto pitonico.

Risposte:


229

Controlla product()nel itertoolsmodulo. Fa esattamente quello che descrivi.

import itertools

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

Questo è equivalente a:

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

Modifica: ci sono anche due funzioni molto simili, permutations()e combinations(). Per illustrare come differiscono:

product() genera ogni possibile accoppiamento di elementi, inclusi tutti i duplicati:

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()genera tutti gli ordinamenti univoci di ogni coppia unica di elementi, eliminando i x,xduplicati:

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

Infine, combinations()genera solo ogni coppia unica di elementi, in ordine lessicografico:

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

Tutte e tre queste funzioni sono state introdotte in Python 2.6.


1
Strano, quando eseguo itertools.product (my_list, 2), si lamenta che int non è richiamabile. Funziona una volta che lo cambio in: itertools.product (my_list, repeat = 2)
ojrac

Notare che itertools.product () è nuovo in Python 2.6.
Mike Mazur,

Solo per i posteri, farò notare che itertools.combinations non genererebbe le linee foo (1,1) o foo (4,4) nell'esempio originale.
Kylotan,

2
Inoltre ci sono combination_with_replacement (). Come le combinazioni (), ma inclusa la diagonale (in linea con le illustrazioni).
Ziegl

1
Per i pigri: per ottenere i risultati di cui sopra permutations()e combinations()utilizzarli r=2al posto di quelli repeat=2usati nell'esempio perproduct()
Rob

15

Ho avuto un problema simile e ho trovato la soluzione qui . Funziona senza dover importare alcun modulo.

Supponendo un elenco come:

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

Una soluzione a una riga semplificata sarebbe simile a questa.

Tutte le possibili coppie , inclusi i duplicati:

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

Tutte le possibili coppie, esclusi i duplicati :

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

Coppie uniche , dove l'ordine è irrilevante:

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

Nel caso in cui non si desideri operare ma solo per ottenere le coppie, foosarebbe sufficiente rimuovere la funzione e utilizzare solo una tupla.

Tutte le possibili coppie , inclusi i duplicati:

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

Risultato:

('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')

Tutte le possibili coppie, esclusi i duplicati :

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

Risultato:

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

Coppie uniche , dove l'ordine è irrilevante:

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

Risultato:

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

Modifica: dopo la rielaborazione per semplificare questa soluzione, ho capito che è lo stesso approccio di Adam Rosenfield. Spero che la spiegazione più ampia aiuti alcuni a capirla meglio.


2
Lo preferisco di gran lunga all'importazione di una libreria, molto più pulita!
sudo-nim

itertools fa parte di Python. Non è una libreria esterna.
GuiSim

2

Se stai solo chiamando una funzione, non puoi fare molto meglio di:

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

Se vuoi raccogliere un elenco dei risultati della chiamata alla funzione, puoi fare:

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

che ti restituirà un elenco del risultato dell'applicazione foo(i, j)a ciascuna coppia possibile (i, j).


0
my_list = [1,2,3,4]

pairs=[[x,y] for x in my_list for y in my_list]
print (pairs)

Sebbene questo codice possa risolvere il problema, una buona risposta richiede anche una spiegazione di ciò che fa il codice e di come risolve il problema.
BDL
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.