Opération sur chaque paire d'éléments dans une liste

95

En utilisant Python, j'aimerais comparer toutes les paires possibles dans une liste.

Supposons que j'ai

my_list = [1,2,3,4]

J'aimerais faire une opération (appelons-le foo) sur chaque combinaison de 2 éléments de la liste.

Le résultat final doit être le même que

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

Ma première pensée a été de parcourir manuellement deux fois la liste, mais cela ne semble pas très pythonique.

GuiSim
la source

Réponses:

231

Vérifiez product()dans le itertoolsmodule. Il fait exactement ce que vous décrivez.

import itertools

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

Cela équivaut à:

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

Edit: Il existe également deux fonctions très similaires, permutations()et combinations(). Pour illustrer leurs différences:

product() génère toutes les paires d'éléments possibles, y compris tous les doublons:

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()génère tous les ordres uniques de chaque paire d'éléments unique, éliminant les x,xdoublons:

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

Enfin, combinations()ne génère que chaque paire unique d'éléments, dans l'ordre lexicographique:

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

Ces trois fonctions ont été introduites dans Python 2.6.

Ben Blank
la source
1
Bizarre, quand je lance itertools.product (ma_liste, 2), il se plaint que int n'est pas appelable. Fonctionne une fois que je l'ai changé en: itertools.product (ma_liste, répéter = 2)
ojrac
Notez que itertools.product () est nouveau dans Python 2.6.
Mike Mazur
Juste pour la postérité, je ferai remarquer que itertools.combinations ne générerait pas les lignes foo (1,1) ou foo (4,4) dans l'exemple d'origine.
Kylotan
2
Il y a aussi combinaisons_with_replacement (). Comme les combinaisons (), mais en incluant la diagonale (en accord avec les illustrations).
Ziegl
1
Pour les paresseux: pour obtenir les résultats ci-dessus avec permutations()et combinations()utiliser r=2à la place de repeat=2utilisé sur l'exemple pourproduct()
Rob
15

J'ai eu un problème similaire et j'ai trouvé la solution ici . Cela fonctionne sans avoir à importer de module.

Supposons une liste comme:

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

Une solution simplifiée en une ligne ressemblerait à ceci.

Toutes les paires possibles , y compris les doublons:

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

Toutes les paires possibles, à l'exclusion des doublons :

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

Paires uniques , où l'ordre n'est pas pertinent:

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

Au cas où vous ne voudriez pas opérer mais juste pour obtenir les paires, supprimer la fonction fooet utiliser juste un tuple suffirait.

Toutes les paires possibles , y compris les doublons:

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

Résultat:

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

Toutes les paires possibles, à l'exclusion des doublons :

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

Résultat:

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

Paires uniques , où l'ordre n'est pas pertinent:

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

Résultat:

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

Edit: Après la refonte pour simplifier cette solution, j'ai réalisé que c'était la même approche qu'Adam Rosenfield. J'espère que l'explication plus large aidera certains à mieux la comprendre.

J0ANMM
la source
2
Je préfère largement cela à l'importation d'une bibliothèque, beaucoup plus propre!
sudo-nim
itertools fait partie de Python. Ce n'est pas une bibliothèque externe.
GuiSim
2

Si vous appelez simplement une fonction, vous ne pouvez pas vraiment faire mieux que:

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

Si vous souhaitez collecter une liste des résultats de l'appel de la fonction, vous pouvez faire:

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

qui vous renverra une liste du résultat de l'application foo(i, j)à chaque paire possible (i, j).

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

pairs=[[x,y] for x in my_list for y in my_list]
print (pairs)
Karan Dave
la source
Bien que ce code puisse résoudre le problème, une bonne réponse nécessite également une explication de ce que fait le code et de la manière dont il résout le problème.
BDL