vérifiez si tous les éléments d'une liste sont identiques
j'ai besoin de la fonction suivante:
Entrée : un list
Sortie :
-
True
si tous les éléments de la liste d'entrée sont évalués comme égaux les uns aux autres en utilisant l'opérateur d'égalité standard; -
False
dans le cas contraire.
Performance : bien sûr, je préfère pas de frais généraux inutiles.
je pense qu'il serait préférable de:
- parcourir la liste
- comparer les éléments adjacents
- et
AND
toutes les valeurs booléennes résultantes
mais je ne sais pas quelle est la façon la plus pythonique de le faire.
modifier :
je vous Remercie pour toutes les réponses grands. J'en ai noté plusieurs, et il était vraiment difficile de choisir entre les solutions @KennyTM et @Ivo van der Wijk.
l'absence de fonction de court-circuit ne fait de mal que sur une entrée longue (plus de ~50 éléments) qui ont tôt des éléments inégaux. Si cela se produit assez souvent (la fréquence dépend de la longueur des listes), le court-circuit est nécessaire. Le meilleur algorithme de court-circuit semble être @KennyTM checkEqual1
. Il paie, cependant, un coût important pour cela:
- jusqu'à 20x en performances listes presque identiques
- jusqu'à 2,5 x en performances sur listes courtes
si les entrées longues avec des éléments inégaux au début ne se produisent pas (ou se produisent assez rarement), le court-circuit n'est pas nécessaire. Puis, de loin la plus rapide est @Ivo van der Wijk solution.
21 réponses
méthode générale:
def checkEqual1(iterator):
iterator = iter(iterator)
try:
first = next(iterator)
except StopIteration:
return True
return all(first == rest for rest in iterator)
One-liner:
def checkEqual2(iterator):
return len(set(iterator)) <= 1
aussi une doublure:
def checkEqual3(lst):
return lst[1:] == lst[:-1]
la différence entre les 3 versions est que:
- Dans
checkEqual2
le contenu doit être hashable. -
checkEqual1
etcheckEqual2
peuvent utiliser toutes les itérateurs, maischeckEqual3
doit prendre une séquence d'entrée, généralement en béton conteneurs comme une liste ou n-uplet. -
checkEqual1
s'arrête dès qu'un écart est constaté. - depuis que
checkEqual1
contient plus de code Python, il est moins efficace quand beaucoup d'éléments sont égaux au début. - depuis
checkEqual2
etcheckEqual3
effectuent toujours des opérations de copie O(N), elles prendront plus de temps si la plupart de vos entrées retourneront False. - pour
checkEqual2
etcheckEqual3
il est plus difficile de s'adapter comparaison dea == b
àa is b
.
timeit
résultat, pour Python 2.7 et (seulement s1, s4, s7, s9 devrait retourner True)
s1 = [1] * 5000
s2 = [1] * 4999 + [2]
s3 = [2] + [1]*4999
s4 = [set([9])] * 5000
s5 = [set([9])] * 4999 + [set([10])]
s6 = [set([10])] + [set([9])] * 4999
s7 = [1,1]
s8 = [1,2]
s9 = []
nous avons
| checkEqual1 | checkEqual2 | checkEqual3 | checkEqualIvo | checkEqual6502 |
|-----|-------------|-------------|--------------|---------------|----------------|
| s1 | 1.19 msec | 348 usec | 183 usec | 51.6 usec | 121 usec |
| s2 | 1.17 msec | 376 usec | 185 usec | 50.9 usec | 118 usec |
| s3 | 4.17 usec | 348 usec | 120 usec | 264 usec | 61.3 usec |
| | | | | | |
| s4 | 1.73 msec | | 182 usec | 50.5 usec | 121 usec |
| s5 | 1.71 msec | | 181 usec | 50.6 usec | 125 usec |
| s6 | 4.29 usec | | 122 usec | 423 usec | 61.1 usec |
| | | | | | |
| s7 | 3.1 usec | 1.4 usec | 1.24 usec | 0.932 usec | 1.92 usec |
| s8 | 4.07 usec | 1.54 usec | 1.28 usec | 0.997 usec | 1.79 usec |
| s9 | 5.91 usec | 1.25 usec | 0.749 usec | 0.407 usec | 0.386 usec |
Note:
# http://stackoverflow.com/q/3844948/
def checkEqualIvo(lst):
return not lst or lst.count(lst[0]) == len(lst)
# http://stackoverflow.com/q/3844931/
def checkEqual6502(lst):
return not lst or [lst[0]]*len(lst) == lst
une solution plus rapide que l'utilisation de set() qui fonctionne sur des séquences (non itérables) est de simplement compter le premier élément. Cela suppose que la liste n'est pas vide (mais c'est trivial de vérifier, et de décider vous-même ce que le résultat devrait être sur une liste vide)
x.count(x[0]) == len(x)
simples points de repère:
>>> timeit.timeit('len(set(s1))<=1', 's1=[1]*5000', number=10000)
1.4383411407470703
>>> timeit.timeit('len(set(s1))<=1', 's1=[1]*4999+[2]', number=10000)
1.4765670299530029
>>> timeit.timeit('s1.count(s1[0])==len(s1)', 's1=[1]*5000', number=10000)
0.26274609565734863
>>> timeit.timeit('s1.count(s1[0])==len(s1)', 's1=[1]*4999+[2]', number=10000)
0.25654196739196777
le moyen le plus simple et le plus élégant est le suivant:
all(x==myList[0] for x in myList)
(Oui, cela fonctionne même avec le nul de la liste! C'est parce que c'est l'un des rares cas où python est paresseux de la sémantique.)
en ce qui concerne la performance, cela échouera le plus tôt possible, il est donc asymptotiquement optimal.
Un ensemble de comparaison de travail:
len(set(the_list)) == 1
utilisant set
supprime tous les éléments en double.
vous pouvez convertir la liste en un ensemble. Un ensemble ne peut pas avoir de doublons. Ainsi, si tous les éléments de la liste originale sont identiques, l'ensemble n'aura qu'un seul élément.
if len(sets.Set(input_list)) == 1
// input_list has all identical elements.
pour ce que ça vaut, c'est arrivé sur la liste de diffusion Python-ideas récemment. Il s'avère qu'Il ya un itertools recette pour ce faire déjà: 1
def all_equal(iterable):
"Returns True if all the elements are equal to each other"
g = groupby(iterable)
return next(g, True) and not next(g, False)
semble-t-il fonctionne très bien et a quelques belles propriétés.
- courts-circuits: il cessera de consommer des articles de l'itérable dès qu'il trouve le premier non-équivalent article.
- N'exige pas que les articles soient hachables.
- Il est paresseux et ne nécessite O(1) de la mémoire supplémentaire pour faire le chèque.
1 en d'autres termes, Je ne peux pas prendre le crédit de venir avec la solution -- ni ne peux prendre le crédit pour même trouver il.
c'est une autre option, plus rapide que len(set(x))==1
pour les longues listes (utilise le court-circuit)
def constantList(x):
return x and [x[0]]*len(x) == x
C'est une façon simple de le faire:
result = mylist and all(mylist[0] == elem for elem in mylist)
c'est un peu plus compliqué, il engage appel de fonction au-dessus, mais la sémantique est plus clairement énoncée:
def all_identical(seq):
if not seq:
# empty list is False.
return False
first = seq[0]
return all(first == elem for elem in seq)
de Doute, c'est le "plus Pythonic", mais quelque chose comme:
>>> falseList = [1,2,3,4]
>>> trueList = [1, 1, 1]
>>>
>>> def testList(list):
... for item in list[1:]:
... if item != list[0]:
... return False
... return True
...
>>> testList(falseList)
False
>>> testList(trueList)
True
ferait l'affaire.
si vous êtes intéressé par quelque chose d'un peu plus lisible (mais bien sûr pas aussi efficace,) vous pouvez essayer:
def compare_lists(list1, list2):
if len(list1) != len(list2): # Weed out unequal length lists.
return False
for item in list1:
if item not in list2:
return False
return True
a_list_1 = ['apple', 'orange', 'grape', 'pear']
a_list_2 = ['pear', 'orange', 'grape', 'apple']
b_list_1 = ['apple', 'orange', 'grape', 'pear']
b_list_2 = ['apple', 'orange', 'banana', 'pear']
c_list_1 = ['apple', 'orange', 'grape']
c_list_2 = ['grape', 'orange']
print compare_lists(a_list_1, a_list_2) # Returns True
print compare_lists(b_list_1, b_list_2) # Returns False
print compare_lists(c_list_1, c_list_2) # Returns False
je ferais:
not any((x[i] != x[i+1] for i in range(0, len(x)-1)))
comme any
cesse de chercher le itérable dès qu'il trouve une condition True
.
concernant l'utilisation de reduce()
avec lambda
. Voici un code de travail que je pense personnellement est beaucoup plus agréable que certaines des autres réponses.
reduce(lambda x, y: (x[1]==y, y), [2, 2, 2], (True, 2))
renvoie un truple où la première valeur est le booléen si tous les éléments sont identiques ou non.
vérifier si tous les éléments sont égaux au premier.
np.allclose(array, array[0])
convertissez la liste dans l'ensemble puis trouvez le nombre d'éléments dans l'ensemble. Si le résultat est 1, il a des éléments identiques et si non, alors les éléments de la liste ne sont pas identiques.
list1 = [1,1,1]
len(set(list1))
>1
list1 = [1,2,3]
len(set(list1)
>3
Voici deux façons simples de le faire
utilisant set ()
lors de la conversion de la liste en un ensemble, les éléments dupliqués sont supprimés. Donc si la longueur de l'ensemble converti est 1, alors cela implique que tous les éléments sont les mêmes.
len(set(input_list))==1
voici un exemple
>>> a = ['not', 'the', 'same']
>>> b = ['same', 'same', 'same']
>>> len(set(a))==1 # == 3
False
>>> len(set(b))==1 # == 1
True
à l'aide de tous()
comparera (équivalence) la première élément de la liste d'entrée pour tous les autres éléments de la liste. Si tous sont équivalents Vrai sera retourné, sinon False sera retourné.
all(element==input_list[0] for element in input_list)
voici un exemple
>>> a = [1, 2, 3, 4, 5]
>>> b = [1, 1, 1, 1, 1]
>>> all(number==a[0] for number in a)
False
>>> all(number==b[0] for number in b)
True
P. S Si vous vérifiez si la liste entière est équivalente à une certaine valeur, vous pouvez suivre la valeur de input_list[0].
>>> a = [1, 2, 3, 4, 5, 6]
>>> z = [(a[x], a[x+1]) for x in range(0, len(a)-1)]
>>> z
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]
# Replacing it with the test
>>> z = [(a[x] == a[x+1]) for x in range(0, len(a)-1)]
>>> z
[False, False, False, False, False]
>>> if False in z : Print "All elements are not equal"
def allTheSame(i):
j = itertools.groupby(i)
for k in j: break
for k in j: return False
return True
fonctionne en Python 2.4, qui n'a pas "tout".
peut utiliser la carte et lambda
lst = [1,1,1,1,1,1,1,1,1]
print all(map(lambda x: x == lst[0], lst[1:]))
Vous pouvez le faire:
reduce(and_, (x==yourList[0] for x in yourList), True)
c'est assez ennuyeux que python vous fasse importer les opérateurs comme operator.and_
. À partir de python3, vous devrez également importer functools.reduce
.
(vous ne devez pas utiliser cette méthode parce qu'elle ne se cassera pas si elle trouve des valeurs non égales, mais continuera à examiner la liste entière. Il est juste inclus ici comme une réponse pour l'exhaustivité.)
lambda lst: reduce(lambda a,b:(b,b==a[0] and a[1]), lst, (lst[0], True))[1]
le prochain court-circuit sera:
all(itertools.imap(lambda i:yourlist[i]==yourlist[i+1], xrange(len(yourlist)-1)))
changez la liste en un ensemble. Alors si la taille de l'ensemble est seulement 1, Ils doivent avoir été les mêmes.
if len(set(my_list)) == 1: