Operacja na każdej parze elementów na liście

101

Używając Pythona, chciałbym porównać każdą możliwą parę na liście.

Przypuśćmy, że tak

my_list = [1,2,3,4]

Chciałbym wykonać operację (nazwijmy to foo) na każdej kombinacji 2 elementów z listy.

Ostateczny wynik powinien być taki sam jak

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

Moją pierwszą myślą było ręczne powtórzenie listy dwukrotnie, ale nie wydaje się to zbyt pytoniczne.

GuiSim
źródło

Odpowiedzi:

240

Sprawdź product()w itertoolsmodule. Robi dokładnie to, co opisujesz.

import itertools

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

Jest to równoważne z:

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

Edycja: Istnieją również dwie bardzo podobne funkcje permutations()i combinations(). Aby zilustrować, czym się różnią:

product() generuje wszystkie możliwe pary elementów, w tym wszystkie duplikaty:

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()generuje wszystkie unikalne uporządkowania każdej unikalnej pary elementów, eliminując x,xduplikaty:

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

Wreszcie combinations()generuje tylko każdą unikalną parę elementów w porządku leksykograficznym:

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

Wszystkie trzy funkcje zostały wprowadzone w Pythonie 2.6.

Ben Blank
źródło
1
Dziwne, kiedy uruchamiam itertools.product (my_list, 2), narzeka, że ​​int nie jest wywoływalny. Działa po zmianie na: itertools.product (my_list, repeat = 2)
ojrac
Zauważ, że itertools.product () jest nowością w Pythonie 2.6.
Mike Mazur
Dla potomności wskażę, że itertools.combinations nie wygenerowałoby linii foo (1,1) ani foo (4,4) w oryginalnym przykładzie.
Kylotan
3
Istnieje również complex_with_replacement (). Jak kombinacje (), ale z uwzględnieniem przekątnej (zgodnie z ilustracjami).
Ziegl
1
Dla leniwych: Aby uzyskać powyższe wyniki permutations()i combinations()użyć r=2zamiast ich repeat=2użycia w przykładzie dlaproduct()
Rob
16

Miałem podobny problem i znaleźć rozwiązanie tutaj . Działa bez konieczności importowania żadnego modułu.

Przypuśćmy, że lista taka jak:

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

Tak wyglądałoby uproszczone rozwiązanie jednowierszowe.

Wszystkie możliwe pary , w tym duplikaty:

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

Wszystkie możliwe pary, z wyłączeniem duplikatów :

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

Unikalne pary , w których kolejność nie ma znaczenia:

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

Jeśli nie chcesz operować, ale po prostu uzyskać pary, foowystarczy usunąć funkcję i użyć tylko krotki.

Wszystkie możliwe pary , w tym duplikaty:

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

Wynik:

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

Wszystkie możliwe pary, z wyłączeniem duplikatów :

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

Wynik:

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

Unikalne pary , w których kolejność nie ma znaczenia:

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

Wynik:

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

Edycja: Po przeróbce mającej na celu uproszczenie tego rozwiązania zdałem sobie sprawę, że jest to to samo podejście, co Adam Rosenfield. Mam nadzieję, że szersze wyjaśnienie pomoże niektórym lepiej to zrozumieć.

J0ANMM
źródło
2
Zdecydowanie wolę to od importowania biblioteki, znacznie czystszej!
sudo-nim
1
itertools jest częścią Pythona. To nie jest biblioteka zewnętrzna.
GuiSim,
3

Jeśli po prostu wywołujesz funkcję, nie możesz zrobić nic lepszego niż:

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

Jeśli chcesz zebrać listę wyników wywołania funkcji, możesz:

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

co zwróci listę wyników zastosowania foo(i, j)do każdej możliwej pary (i, j).

Adam Rosenfield
źródło
0
my_list = [1,2,3,4]

pairs=[[x,y] for x in my_list for y in my_list]
print (pairs)
karan dave
źródło
Chociaż ten kod może rozwiązać problem, dobra odpowiedź wymaga również wyjaśnienia, co robi kod i jak rozwiązuje problem.
BDL,