Операція з кожною парою елементів у списку


95

Використовуючи Python, я хотів би порівняти всі можливі пари у списку.

Припустимо, що маю

my_list = [1,2,3,4]

Я хотів би виконати операцію (назвемо це foo) над кожною комбінацією з 2 елементів зі списку.

Кінцевий результат повинен бути таким же, як

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

Моя перша думка полягала в тому, щоб двічі переглядати список вручну, але це здається не надто пітонічним.

Відповіді:


231

Перевірте product()в itertoolsмодулі. Він робить саме те, що ви описуєте.

import itertools

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

Це еквівалентно:

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

Редагувати: Є також дві дуже схожі функції, permutations()іcombinations() . Щоб проілюструвати, чим вони відрізняються:

product() генерує всі можливі сполучення елементів, включаючи всі дублікати:

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()генерує всі унікальні впорядкування кожної унікальної пари елементів, виключаючи x,xдублікати:

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

Нарешті, combinations()лише генерує кожну унікальну пару елементів у лексикографічному порядку:

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

Всі ці три функції були введені в Python 2.6.


1
Дивно, коли я запускаю itertools.product (my_list, 2), він скаржиться, що int не викликається. Працює, коли я його змінюю на: itertools.product (my_list, repeat = 2)
ojrac

Зверніть увагу, що itertools.product () є новим у Python 2.6.
Mike Mazur

Тільки для нащадків я зазначу, що комбінації itertools.com не генеруватимуть рядки foo (1,1) або foo (4,4) у вихідному прикладі.
Кілотан

2
Також є поєднання_з_заміною (). Подібні комбінації (), але включаючи діагональ (відповідно до ілюстрацій).
Ziegl

1
Для ледачих: Для того, щоб отримати вищезгадані результати з permutations()і combinations()використовувати r=2замість repeat=2використовуваних на прикладі дляproduct()
Rob

15

У мене була подібна проблема і я знайшов рішення тут . Це працює без необхідності імпортувати будь-який модуль.

Припустимо такий список, як:

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

Спрощене однорядкове рішення могло б виглядати так.

Усі можливі пари , включаючи дублікати:

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

Усі можливі пари, крім дублікатів :

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

Унікальні пари , де порядок не має значення:

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

Якщо ви не хочете працювати, а просто отримати пари, видаливши функцію foo буде достатньо та використання лише кортежу.

Усі можливі пари , включаючи дублікати:

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

Результат:

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

Усі можливі пари, крім дублікатів :

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

Результат:

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

Унікальні пари , де порядок не має значення:

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

Результат:

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

Редагувати: Після переробки для спрощення цього рішення я зрозумів, що це такий самий підхід, як Адам Розенфілд. Я сподіваюся, що розширене пояснення допомагає деяким зрозуміти це краще.


2
Я віддаю перевагу цьому перед імпортом бібліотеки, набагато чистішої!
судо-нім

itertools є частиною Python. Це не зовнішня бібліотека.
GuiSim

2

Якщо ви просто викликаєте функцію, ви насправді не можете зробити набагато краще, ніж:

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

Якщо ви хочете зібрати список результатів виклику функції, ви можете зробити:

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

який поверне вам список результатів застосування foo(i, j)до кожної можливої ​​пари (i, j).


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

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

Хоча цей код може вирішити проблему, хороша відповідь також вимагає пояснення того, що робить код і як він вирішує проблему.
BDL
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.