92 votes

Comment comparer chaque élément d'une liste avec les autres, une seule fois ?

Disons que j'ai un tableau/une liste de choses que je veux comparer. Dans les langages avec lesquels je suis plus familier, je ferais quelque chose comme

for (int i = 0, i < mylist.size(); i++)
    for (int j = i + 1, j < mylist.size(); j++)
        compare(mylist[i], mylist[j])

Cela garantit que nous ne comparons chaque paire qu'une seule fois. Dans un contexte particulier, je fais de la détection de collision sur un groupe d'objets contenus dans la liste. Pour chaque collision détectée, un petit objet "collision" décrivant la collision est ajouté à une liste, qu'une autre routine parcourt ensuite en boucle pour résoudre chaque collision (en fonction de la nature des deux objets en collision). Évidemment, je ne veux signaler chaque collision qu'une seule fois.

Maintenant, quelle est la façon pythonique de faire cela, puisque Python favorise l'utilisation d'itérateurs plutôt que de boucler sur des indices ?

J'avais le code suivant (bogué) :

for this in mylist:
    for that in mylist:
        compare(this, that)

Mais il est clair que chaque collision est détectée deux fois, ce qui entraîne un comportement étrange lorsqu'on essaie de les résoudre. Quelle est donc la solution pythique ici ?

167voto

poke Points 64398

Bien sûr, cela va générer chaque paire deux fois plus que chaque for La boucle passera en revue tous les éléments de la liste.

Vous pourriez utiliser itertools magique ici pour générer toutes les combinaisons possibles :

import itertools
for a, b in itertools.combinations(mylist, 2):
    compare(a, b)

itertools.combinations va coupler chaque élément avec chaque autre élément de l'itérable, mais seulement une fois.


Vous pouvez toujours écrire ce document en utilisant un accès aux éléments basé sur un index, comme vous en avez l'habitude, en utilisant des éléments imbriqués. for boucles :

for i in range(len(mylist)):
    for j in range(i + 1, len(mylist)):
        compare(mylist[i], mylist[j])

Bien sûr, cela n'a pas l'air aussi joli et pythique, mais c'est parfois la solution la plus simple et la plus compréhensible, et il ne faut pas hésiter à résoudre ce genre de problèmes.

33voto

shx2 Points 14025

Utilisez itertools.combinations(mylist, 2)

mylist = range(5)
for x,y in itertools.combinations(mylist, 2):
    print x,y

0 1
0 2
0 3
0 4
1 2
1 3
1 4
2 3
2 4
3 4

12voto

alan Points 157

Je pense qu'utiliser énumérer dans la boucle externe et l'utilisation de l'index pour découper la liste dans la boucle interne est assez pythonique :

for index, this in enumerate(mylist):
    for that in mylist[index+1:]:
        compare(this, that)

0voto

Shambulinga H Points 13

Trouvez l'autre réponse pour ce programme de manière simple

def Compare_two_list(list_1, list_2):
    data_len = len(list_1)
    for i in range(data_len):
        if list_1[i] <= list_2[i] :
            print("Less than or equal")
        else:
            get_data.append(list_2[i])
            print("greater than")`

-2voto

Osama Zahid Points 27

Ce code va compter les fréquences et supprimer les éléments en double :

from collections import Counter

str1='the cat sat on the hat hat'

int_list=str1.split();

unique_list = []
for el in int_list:

    if el not in unique_list:
        unique_list.append(el)
    else:
        print "Element already in the list"

print unique_list

c=Counter(int_list)

c.values()

c.keys()

print c

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X