comprobar si todos los elementos de una lista son idénticos


Necesito la siguiente función:

Entrada : a list

Salida:

  • True si todos los elementos de la lista de entrada se evalúan como iguales entre sí utilizando el operador de igualdad estándar;
  • False de lo contrario.

Rendimiento : por supuesto, prefiero no incurrir en gastos generales innecesarios.

Creo que sería mejor:

  • iterar a través de la lista
  • comparar adyacente elementos
  • y AND todos los valores booleanos resultantes

Pero no estoy seguro de cuál es la forma más pitónica de hacer eso.


EDITAR :

Gracias por todas las grandes respuestas. Yo nominal de hasta varios, y fue muy difícil elegir entre @KennyTM y @Ivo van der Wijk soluciones.

La falta de función de cortocircuito solo duele en una entrada larga (más de ~50 elementos) que tienen elementos desiguales al principio. Si esto ocurre con la frecuencia suficiente (con qué frecuencia depende de la longitud de las listas), se requiere el cortocircuito. El mejor algoritmo de cortocircuito parece ser @KennyTM checkEqual1. Paga, sin embargo, un costo significativo por esto:

  • hasta 20 veces en listas de rendimiento casi idénticas
  • hasta 2,5 veces en rendimiento en listas cortas

Si las entradas largas con elementos desiguales tempranos no ocurren (o ocurren suficientemente raramente), no se requiere cortocircuito. Entonces, con mucho, el más rápido es @Ivo van der Wijk solución.

Author: jfs, 2010-10-02

21 answers

Método general:

def checkEqual1(iterator):
    iterator = iter(iterator)
    try:
        first = next(iterator)
    except StopIteration:
        return True
    return all(first == rest for rest in iterator)

Una sola línea:

def checkEqual2(iterator):
   return len(set(iterator)) <= 1

También de una sola línea:

def checkEqual3(lst):
   return lst[1:] == lst[:-1]

La diferencia entre las 3 versiones es que:

    {[28] {} En[6]} el contenido debe ser hashable.
  1. checkEqual1 y checkEqual2 pueden usar cualquier iterador, pero checkEqual3 debe tomar una entrada de secuencia, típicamente contenedores de concreto como una lista o tupla.
  2. checkEqual1 se detiene tan pronto como se encuentra una diferencia.
  3. Dado que checkEqual1 contiene más código Python, es menos eficiente cuando muchos de los elementos son iguales al principio.
  4. Dado que checkEqual2 y checkEqual3 siempre realizan operaciones de copia O(N), tardarán más si la mayor parte de su entrada devuelve False.
  5. Para checkEqual2 y checkEqual3 es más difícil adaptar la comparación de a == b a a is b.

timeit resultado, para Python 2.7 y (solo s1, s4, s7, s9 debe devolver 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 = []

Obtenemos

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

Nota:

# 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
Author: kennytm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-11 21:38:35

Una solución más rápida que usar set() que funciona en secuencias (no iterables) es simplemente contar el primer elemento. Esto asume que la lista no está vacía (pero eso es trivial de verificar y decidir por ti mismo cuál debe ser el resultado en una lista vacía)

x.count(x[0]) == len(x)

Algunos puntos de referencia simples:

>>> 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
Author: Ivo van der Wijk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-10-02 08:25:21

La forma más simple y elegante es la siguiente:

all(x==myList[0] for x in myList)

(¡Sí, esto incluso funciona con la lista nula! Esto se debe a que este es uno de los pocos casos en los que python tiene semántica perezosa.)

En cuanto al rendimiento, esto fallará lo antes posible, por lo que es asintóticamente óptimo.

 103
Author: ninjagecko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-24 20:49:58

Un trabajo de comparación de conjuntos:

len(set(the_list)) == 1

Usando set elimina todos los elementos duplicados.

 30
Author: cbalawat,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-10-16 01:06:34

Puede convertir la lista a un conjunto. Un conjunto no puede tener duplicados. Así que si todos los elementos de la lista original son idénticos, el conjunto tendrá solo un elemento.

if len(sets.Set(input_list)) == 1
// input_list has all identical elements.
 23
Author: codaddict,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-10-02 07:51:52

Por si sirve de algo, esto surgió recientemente en la lista de correo de python-ideas. Resulta que hay una receta de itertools para hacer esto ya: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)

Supuestamente funciona muy bien y tiene algunas propiedades agradables.

  1. Cortocircuitos: Dejará de consumir elementos del iterable tan pronto como encuentre el primer elemento no igual.
  2. No requiere que los elementos sean hashables.
  3. Es perezoso y solo requiere O (1) memoria adicional para hacer la comprobación.

1En otras palabras, no puedo tomar el crédito para llegar a la solución nor ni puedo tomar el crédito para incluso encontrar.

 12
Author: mgilson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-10-06 23:16:59

Esta es otra opción, más rápida que len(set(x))==1 para listas largas (usa cortocircuito)

def constantList(x):
    return x and [x[0]]*len(x) == x
 10
Author: 6502,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-10-02 08:22:50

Esta es una forma sencilla de hacerlo:

result = mylist and all(mylist[0] == elem for elem in mylist)

Esto es un poco más complicado, incurre en sobrecarga de llamadas a funciones, pero la semántica está más claramente explicada:

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
Author: Jerub,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-10-02 08:11:43

Duda que este es el "más pitónico", pero algo así como:

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

Haría el truco.

 4
Author: machineghost,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-10-02 07:39:45

Si usted está interesado en algo un poco más legible (pero por supuesto no tan eficiente,) usted podría intentar:

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
Author: Joshua Burns,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-06-04 20:22:01

Yo haría:

not any((x[i] != x[i+1] for i in range(0, len(x)-1)))

Como any deja de buscar el iterable tan pronto como encuentra una condición True.

 3
Author: Robert Rossney,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-13 18:19:47

Con respecto a usar reduce() con lambda. Aquí hay un código de trabajo que personalmente creo que es mucho más agradable que algunas de las otras respuestas.

reduce(lambda x, y: (x[1]==y, y), [2, 2, 2], (True, 2))

Devuelve una truple donde el primer valor es el booleano si todos los elementos son iguales o no.

 3
Author: Marcus Lind,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-10-21 08:51:48

Compruebe si todos los elementos son iguales al primero.

np.allclose(array, array[0])

 3
Author: Gusev Slava,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-26 14:59:45

Convierta la lista en el conjunto y luego encuentre el número de elementos en el conjunto. Si el resultado es 1, tiene elementos idénticos y si no, entonces los elementos de la lista no son idénticos.

list1 = [1,1,1]
len(set(list1)) 
>1

list1 = [1,2,3]
len(set(list1)
>3
 3
Author: DePP,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-26 06:02:29

Aquí hay dos formas simples de hacer esto

Usando set ()

Al convertir la lista a un conjunto, se eliminan los elementos duplicados. Así que si la longitud del conjunto convertido es 1, entonces esto implica que todos los elementos son los mismos.

len(set(input_list))==1

He aquí un ejemplo

>>> a = ['not', 'the', 'same']
>>> b = ['same', 'same', 'same']
>>> len(set(a))==1  # == 3
False
>>> len(set(b))==1  # == 1
True

Usando all ()

Esto comparará (equivalencia) el primer elemento de la lista de entrada con todos los demás elementos de la lista. Si todos son equivalentes True será devuelto, de lo contrario False será devuelto.

all(element==input_list[0] for element in input_list)

He aquí un ejemplo

>>> 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 usted está comprobando para ver si la lista entera es equivalente a un cierto valor, usted puede suibstitue el valor adentro para input_list [0].

 3
Author: Christopher Nuccio,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
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
Author: pyfunc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
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

Funciona en Python 2.4, que no tiene "todo".

 2
Author: itertool,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-10 06:28:29

Puede usar map y lambda

lst = [1,1,1,1,1,1,1,1,1]

print all(map(lambda x: x == lst[0], lst[1:]))
 2
Author: Vikram S,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-04-13 05:22:56

Puedes hacer:

reduce(and_, (x==yourList[0] for x in yourList), True)

Es bastante molesto que python te haga importar operadores como operator.and_. A partir de python3, también necesitarás importar functools.reduce.

(No debe usar este método porque no se romperá si encuentra valores no iguales, sino que continuará examinando toda la lista. Solo se incluye aquí como una respuesta para completar.)

 1
Author: ninjagecko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-04-24 17:40:02
lambda lst: reduce(lambda a,b:(b,b==a[0] and a[1]), lst, (lst[0], True))[1]

El próximo cortocircuito cortocircuito:

all(itertools.imap(lambda i:yourlist[i]==yourlist[i+1], xrange(len(yourlist)-1)))
 1
Author: user3015260,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-03-27 09:46:25

Cambie la lista a un conjunto. Entonces, si el tamaño del conjunto es solo 1, deben haber sido el mismo.

if len(set(my_list)) == 1:
 1
Author: Lumo5,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-02-15 08:34:42