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.

271
demandé sur jfs 2010-10-02 11:31:11

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:

  1. Dans checkEqual2 le contenu doit être hashable.
  2. checkEqual1 et checkEqual2 peuvent utiliser toutes les itérateurs, mais checkEqual3 doit prendre une séquence d'entrée, généralement en béton conteneurs comme une liste ou n-uplet.
  3. checkEqual1 s'arrête dès qu'un écart est constaté.
  4. depuis que checkEqual1 contient plus de code Python, il est moins efficace quand beaucoup d'éléments sont égaux au début.
  5. depuis checkEqual2 et checkEqual3 effectuent toujours des opérations de copie O(N), elles prendront plus de temps si la plupart de vos entrées retourneront False.
  6. pour checkEqual2 et checkEqual3 il est plus difficile de s'adapter comparaison de a == 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
310
répondu kennytm 2018-08-11 21:38:35

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
231
répondu Ivo van der Wijk 2010-10-02 08:25:21

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.

103
répondu ninjagecko 2016-07-24 20:49:58

Un ensemble de comparaison de travail:

len(set(the_list)) == 1

utilisant set supprime tous les éléments en double.

30
répondu cbalawat 2017-10-16 01:06:34

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.
23
répondu codaddict 2010-10-02 07:51:52

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.

  1. courts-circuits: il cessera de consommer des articles de l'itérable dès qu'il trouve le premier non-équivalent article.
  2. N'exige pas que les articles soient hachables.
  3. 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.

12
répondu mgilson 2016-10-06 23:16:59

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
10
répondu 6502 2010-10-02 08:22:50

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)
6
répondu Jerub 2010-10-02 08:11:43

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.

4
répondu machineghost 2010-10-02 07:39:45

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
4
répondu Joshua Burns 2012-06-04 20:22:01

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 .

3
répondu Robert Rossney 2012-01-13 18:19:47

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.

3
répondu Marcus Lind 2015-10-21 08:51:48

vérifier si tous les éléments sont égaux au premier.

np.allclose(array, array[0])

3
répondu Gusev Slava 2016-12-26 14:59:45

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
3
répondu DePP 2018-03-26 06:02:29

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].

3
répondu Christopher Nuccio 2018-07-24 18:47:42
>>> 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"
2
répondu pyfunc 2010-10-02 07:45:27
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".

2
répondu itertool 2012-01-10 06:28:29

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:]))
2
répondu Vikram S 2017-04-13 05:22:56

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é.)

1
répondu ninjagecko 2012-04-24 17:40:02
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)))
1
répondu user3015260 2014-03-27 09:46:25

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:
1
répondu Lumo5 2018-02-15 08:34:42