Работа с каждой парой элементов в списке

104

Используя Python, я хотел бы сравнить все возможные пары в списке.

Предположим, у меня есть

my_list = [1,2,3,4]

Я хотел бы выполнить операцию (назовем ее foo) над каждой комбинацией двух элементов из списка.

Конечный результат должен быть таким же, как

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

Моя первая мысль заключалась в том, чтобы дважды перебрать список вручную, но это не кажется очень питоническим.

GuiSim
источник

Ответы:

244

Проверить 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.
Майк Мазур
Для потомков я отмечу, что itertools.combinations не будет генерировать строки foo (1,1) или foo (4,4) в исходном примере.
Kylotan
3
Также есть комбинации_with_replacement (). Аналогичные сочетаниям (), но с учетом диагонали (в соответствии с иллюстрациями).
Ziegl
1
Для ленивых: чтобы получить вышеуказанные результаты permutations()и combinations()использовать r=2вместо repeat=2использованного в примере дляproduct()
Роб
16

У меня была аналогичная проблема, и я нашел решение здесь . Он работает без необходимости импорта какого-либо модуля.

Допустим, список вроде:

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

Изменить: после переделки, чтобы упростить это решение, я понял, что это тот же подход, что и у Адама Розенфилда. Я надеюсь, что более подробное объяснение поможет некоторым лучше понять это.

J0ANMM
источник
2
Я предпочитаю это импортировать библиотеку, намного чище!
sudo-nim
1
itertools является частью Python. Это не внешняя библиотека.
GuiSim 05
3

Если вы просто вызываете функцию, вы не сможете добиться большего, чем:

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