web-dev-qa-db-fra.com

Vérifier si deux listes non ordonnées sont égales

Je cherche un moyen simple (et rapide) de déterminer si deux listes non numérotées contiennent les mêmes éléments:

Par exemple:

['one', 'two', 'three'] == ['one', 'two', 'three'] :  true
['one', 'two', 'three'] == ['one', 'three', 'two'] :  true
['one', 'two', 'three'] == ['one', 'two', 'three', 'three'] :  false
['one', 'two', 'three'] == ['one', 'two', 'three', 'four'] :  false
['one', 'two', 'three'] == ['one', 'two', 'four'] :  false
['one', 'two', 'three'] == ['one'] :  false

J'espère pouvoir le faire sans utiliser de carte.

224
Paul

Python a un type de données intégré pour une collection non ordonnée de choses (pouvant être remplies), appelée set. Si vous convertissez les deux listes en ensembles, la comparaison sera non ordonnée.

_set(x) == set(y)
_

Documentation sur set


EDIT: @mdwhatcott indique que vous souhaitez vérifier les doublons. set les ignore, vous avez donc besoin d'une structure de données similaire qui garde également une trace du nombre d'éléments dans chaque liste. Ceci s'appelle un multiset ; la meilleure approximation dans la bibliothèque standard est un collections.Counter :

_>>> import collections
>>> compare = lambda x, y: collections.Counter(x) == collections.Counter(y)
>>> 
>>> compare([1,2,3], [1,2,3,3])
False
>>> compare([1,2,3], [1,2,3])
True
>>> compare([1,2,3,3], [1,2,2,3])
False
>>> 
_
395
Katriel

Si les éléments sont toujours presque triés comme dans votre exemple, alors la fonction .sort() ( timsort ) devrait être rapide:

>>> a = [1,1,2]
>>> b = [1,2,2]
>>> a.sort()
>>> b.sort()
>>> a == b
False

Si vous ne voulez pas trier sur place, vous pouvez utiliser sorted() .

En pratique, il pourrait toujours être plus rapide que collections.Counter() (malgré le fait que O(n) soit asymptotiquement meilleur que le O(n*log(n)) pour .sort()). Mesure le; Si c'est important.

65
jfs
sorted(x) == sorted(y)

Copier à partir d'ici: Vérifier si deux listes non ordonnées sont égales

Je pense que c'est la meilleure réponse à cette question parce que

  1. C'est mieux que d'utiliser un compteur comme indiqué dans cette réponse
  2. x.sort () trie x, qui est un effet secondaire. trié (x) renvoie une nouvelle liste.
17
Enzam Hossain

Vous voulez voir s'ils contiennent les mêmes éléments, mais ne vous souciez pas de la commande.

Vous pouvez utiliser un ensemble:

>>> set(['one', 'two', 'three']) == set(['two', 'one', 'three'])
True

Mais l'objet set lui-même ne contiendra qu'une instance de chaque valeur unique et ne préservera pas l'ordre.

>>> set(['one', 'one', 'one']) == set(['one'])
True

Donc, si le suivi des doublons/longueur est important, vous voudrez probablement également vérifier la longueur:

def are_eq(a, b):
    return set(a) == set(b) and len(a) == len(b)
14
Matimus

si vous ne souhaitez pas utiliser la bibliothèque de collections, vous pouvez toujours faire quelque chose comme ceci: étant donné que a et b sont vos listes, les éléments suivants renvoient le nombre d'éléments correspondants (il tient compte de l'ordre) .

sum([1 for i,j in Zip(a,b) if i==j])

Donc,

len(a)==len(b) and len(a)==sum([1 for i,j in Zip(a,b) if i==j])

sera True si les deux listes sont identiques, contiennent les mêmes éléments et dans le même ordre. False sinon.

Vous pouvez donc définir la fonction de comparaison comme pour la première réponse ci-dessus, mais sans la bibliothèque de collections.

compare = lambda a,b: len(a)==len(b) and len(a)==sum([1 for i,j in Zip(a,b) if i==j])

et

>>> compare([1,2,3], [1,2,3,3])
False
>>> compare([1,2,3], [1,2,3])
True
>>> compare([1,2,3], [1,2,4])
False
4
fiacobelli

Une réponse à la question ci-dessus est la suivante: -

laissez les deux listes être list1 et list2, et votre exigence est de vous assurer que deux listes comportent les mêmes éléments, puis, selon moi, voici la meilleure approche: -

if ((len(list1) == len(list2)) and
   (all(i in list2 for i in list1))):
    print 'True'
else:
    print 'False'

Le code ci-dessus fonctionnera selon vos besoins, c'est-à-dire si tous les éléments de list1 sont dans list2 et vice-verse.

Mais si vous voulez juste vérifier si tous les éléments de list1 sont présents dans list2 ou non, alors vous devez utiliser le code ci-dessous uniquement: -

if all(i in list2 for i in list1):
    print 'True'
else:
    print 'False'

La différence est que le dernier imprimera True, si list2 contient des éléments supplémentaires ainsi que tous les éléments de list1. En termes simples, cela garantira que tous les éléments de list1 seront présents dans list2, que list2 comporte ou non des éléments supplémentaires.

3
Pabitra Pati

Qu'en est-il d'obtenir la représentation sous forme de chaîne des listes et de les comparer?

>>> l1 = ['one', 'two', 'three']
>>> l2 = ['one', 'two', 'three']
>>> l3 = ['one', 'three', 'two']
>>> print str(l1) == str(l2)
True
>>> print str(l1) == str(l3)
False
3
sagi

En supposant que vous sachiez déjà que les listes ont la même taille, les éléments suivants garantiront la valeur True si et seulement si deux vecteurs sont exactement identiques (ordre compris)

functools.reduce(lambda b1,b2: b1 and b2, map(lambda e1,e2: e1==e2, listA, ListB), True)

Exemple:

>>> from functools import reduce
>>> def compvecs(a,b):
...     return reduce(lambda b1,b2: b1 and b2, map(lambda e1,e2: e1==e2, a, b), True)
... 
>>> compvecs(a=[1,2,3,4], b=[1,2,4,3])
False
>>> compvecs(a=[1,2,3,4], b=[1,2,3,4])
True
>>> compvecs(a=[1,2,3,4], b=[1,2,4,3])
False
>>> compare_vectors(a=[1,2,3,4], b=[1,2,2,4])
False
>>> 
3
Arnon Sela