J'ai besoin de la fonction suivante:
Entrée : alist
Sortie :
True
si tous les éléments de la liste d'entrée sont évalués comme égaux les uns aux autres à l'aide de l'opérateur d'égalité standard;False
autrement.
Performance : bien sûr, je préfère ne pas encourir 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.
L'absence de fonction de court-circuit ne fait mal que sur une longue entrée (plus de ~ 50 éléments) qui a des éléments inégaux dès le début. Si cela se produit assez souvent (la fréquence dépend de la durée 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 dans des listes de performances presque identiques
- jusqu'à 2,5 fois les performances sur les listes restreintes
Si les entrées longues avec des éléments inégaux précoces ne se produisent pas (ou se produisent suffisamment rarement), un court-circuit n'est pas nécessaire. La solution @Ivo van der Wijk est de loin la plus rapide.
a == b
ou identique àa is b
?functools.reduce(operator.eq, a)
ne pas avoir été suggéré.Réponses:
Méthode générale:
Bon mot:
Également une ligne:
La différence entre les 3 versions est que:
checkEqual2
le contenu doit être lavable.checkEqual1
etcheckEqual2
peut utiliser n'importe quel itérateur, maischeckEqual3
doit prendre une entrée de séquence, généralement des conteneurs concrets comme une liste ou un tuple.checkEqual1
s'arrête dès qu'une différence est trouvée.checkEqual1
contient plus de code Python, il est moins efficace lorsque de nombreux éléments sont égaux au début.checkEqual2
etcheckEqual3
toujours effectuer des opérations de copie O (N), elles prendront plus de temps si la plupart de vos entrées renvoient False.checkEqual2
etcheckEqual3
il est plus difficile d'adapter la comparaison dea == b
àa is b
.timeit
résultat, pour Python 2.7 et (seuls s1, s4, s7, s9 devraient renvoyer True)on a
Remarque:
la source
obj.__eq__
quandlhs is rhs
, et des optimisations dans le désordre pour permettre de court-circuiter les listes triées plus rapidement.itertools
recette que j'ai ajoutée comme réponse. Cela vaut peut-être la peine de le jeter dans votre matrice de chronométrage :-).Une solution plus rapide que l'utilisation de set () qui fonctionne sur des séquences (et non sur des itérables) consiste à simplement compter le premier élément. Cela suppose que la liste n'est pas vide (mais c'est trivial à vérifier, et décidez vous-même quel devrait être le résultat sur une liste vide)
quelques repères simples:
la source
x.count(next(x)) == len(x)
afin qu'il fonctionne pour n'importe quel conteneur x? Ahh .. nm, je viens de voir que .count n'est disponible que pour les séquences .. Pourquoi n'est-il pas implémenté pour d'autres conteneurs intégrés? Compter dans un dictionnaire est-il intrinsèquement moins significatif que dans une liste?count
n'est pas implémenté pour les itérables, pas pourquoilen
n'est pas disponible pour les itérateurs. La réponse est probablement que ce n'est qu'un oubli. Mais c'est inutile pour nous car le défaut.count()
pour les séquences est très lent (pur python). La raison pour laquelle votre solution est si rapide est qu'elle repose sur l'implémentation Ccount
fournie parlist
. Donc, je suppose que ce qui se produit pour implémenter lacount
méthode en C bénéficiera de votre approche.La manière la plus simple et la plus élégante est la suivante:
(Oui, cela fonctionne même avec la liste vide! C'est parce que c'est l'un des rares cas où python a une sémantique paresseuse.)
En ce qui concerne les performances, cela échouera le plus tôt possible, donc c'est asymptotiquement optimal.
la source
checkEqual1
. Je ne sais pas pourquoi.first=myList[0]
all(x==first for x in myList)
, peutfirst=myList[0]
mettra unIndexError
sur une liste vide, donc les commentateurs qui parlaient de cette optimisation que j'ai mentionnée devront faire face au cas de bord d'une liste vide. Cependant l'original est très bien (x==myList[0]
est bien dans leall
car il n'est jamais évalué si la liste est vide).Un travail de comparaison défini:
L'utilisation
set
supprime tous les éléments en double.la source
Vous pouvez convertir la liste en un ensemble. Un ensemble ne peut pas avoir de doublons. Donc, si tous les éléments de la liste d'origine sont identiques, l'ensemble n'aura qu'un seul élément.
la source
len(set(input_list)) == 1
?Pour ce que ça vaut, cela est apparu sur la liste de diffusion python-ideas récemment. Il s'avère qu'il existe déjà une recette itertools pour le faire: 1
Soi-disant, il fonctionne très bien et a quelques belles propriétés.
1 En d'autres termes, je ne peux pas m'attribuer le mérite d'avoir trouvé la solution, ni même l' avoir trouvée .
la source
return next(g, f := next(g, g)) == f
(à partir de py3.8 bien sûr)Voici deux façons simples de procéder
en utilisant set ()
Lors de la conversion de la liste en un ensemble, les éléments en double sont supprimés. Donc, si la longueur de l'ensemble converti est 1, cela implique que tous les éléments sont identiques.
Voici un exemple
en utilisant tout ()
Cela comparera (équivalence) le premier élément de la liste d'entrée à tous les autres éléments de la liste. Si tous sont équivalents, True sera retourné, sinon False sera retourné.
Voici un exemple
PS Si vous vérifiez si la liste entière est équivalente à une certaine valeur, vous pouvez remplacer la valeur dans pour input_list [0].
la source
len(set(a))
sur une liste de 10 000 000 d'éléments a pris 0,09 s tandis que l'exécution aall
pris 0,9 s (10 fois plus).Ceci est une autre option, plus rapide que
len(set(x))==1
pour les longues listes (utilise un court-circuit)la source
C'est une manière simple de le faire:
C'est un peu plus compliqué, cela entraîne une surcharge d'appels de fonction, mais la sémantique est plus clairement énoncée:
la source
for elem in mylist[1:]
. Je doute que cela améliore beaucoup la vitesse, car je supposeelem[0] is elem[0]
que l'interprète peut probablement faire cette comparaison très rapidement.Vérifiez si tous les éléments sont égaux au premier.
np.allclose(array, array[0])
la source
Je doute que ce soit le "plus Pythonique", mais quelque chose comme:
ferait l'affaire.
la source
for
boucle peut être rendue plus Pythoniqueif any(item != list[0] for item in list[1:]): return False
, avec exactement la même sémantique.Si vous êtes intéressé par quelque chose d'un peu plus lisible (mais bien sûr pas aussi efficace), vous pouvez essayer:
la source
Convertissez la liste en ensemble, puis recherchez le nombre d'éléments dans l'ensemble. Si le résultat est 1, il a des éléments identiques et sinon, les éléments de la liste ne sont pas identiques.
la source
Concernant l'utilisation
reduce()
aveclambda
. Voici un code de travail qui, à mon avis, est bien plus agréable que certaines des autres réponses.Renvoie un tuple dont la première valeur est le booléen si tous les éléments sont identiques ou non.
la source
[1, 2, 2]
): il ne prend pas en compte la valeur booléenne précédente. Cela peut être corrigé en remplaçantx[1] == y
parx[0] and x[1] == y
.Je ferais:
as
any
arrête de rechercher l'itérable dès qu'il trouve uneTrue
condition.la source
all()
pourquoi ne pas utiliserall(x == seq[0] for x in seq)
? semble plus pythonique et devrait effectuer la même chosela source
Fonctionne en Python 2.4, qui n'a pas "tout".
la source
for k in j: break
est équivalent ànext(j)
. Vous auriez également pu le fairedef allTheSame(x): return len(list(itertools.groupby(x))<2)
si vous ne vous souciez pas de l'efficacité.Peut utiliser la carte et lambda
la source
Ou utilisez la
diff
méthode de numpy:Et pour appeler:
Production:
la source
not np.any(np.diff(l))
pourrait être un peu plus rapide.Ou utilisez la méthode diff de numpy:
Et pour appeler:
Production:
Vrai
la source
Tu peux faire:
Il est assez ennuyeux que python vous fasse importer les opérateurs comme
operator.and_
. À partir de python3, vous devrez également importerfunctools.reduce
.(Vous ne devez pas utiliser cette méthode car elle ne se cassera pas si elle trouve des valeurs non égales, mais continuera à examiner la liste entière. Elle est juste incluse ici comme réponse pour être complète.)
la source
Le prochain court-circuitera:
la source
reduce(lambda a,b:a==b, [2,2,2])
cèdeFalse
... Je l'ai édité, mais de cette façon il n'est plus joliModifiez la liste en un ensemble. Ensuite, si la taille de l'ensemble n'est que de 1, elles doivent être identiques.
la source
Il existe également une option récursive Python pure:
Cependant, pour une raison quelconque, il est dans certains cas deux ordres de grandeur plus lent que les autres options. Venant de la mentalité du langage C, je m'attendais à ce que ce soit plus rapide, mais ce n'est pas le cas!
L'autre inconvénient est qu'il existe une limite de récursivité en Python qui doit être ajustée dans ce cas. Par exemple en utilisant ceci .
la source
Vous pouvez utiliser
.nunique()
pour rechercher le nombre d'éléments uniques dans une liste.la source
vous pouvez utiliser
set
. Il fera un ensemble et supprimera les éléments répétitifs. Vérifiez ensuite qu'il ne contient pas plus d'un élément.Exemple:
la source