compruebe si todos los elementos en una lista son idénticos

Necesito la siguiente función:

Entrada : una 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 contrario.

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

Siento que sería mejor:

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

Pero no estoy seguro de cuál es la forma más pythonica de hacerlo.


EDITAR :

Gracias por todas las grandes respuestas. Clasifiqué varios, y fue realmente difícil elegir entre las soluciones @KennyTM y @Ivo van der Wijk.

La falta de la función de cortocircuito solo afecta a una entrada larga (más de 50 elementos) que tiene elementos desiguales desde el principio. Si esto ocurre con la frecuencia suficiente (la frecuencia depende de la duración de las listas), se requiere el cortocircuito. El mejor algoritmo de cortocircuito parece ser @KennyTM checkEqual1 . Paga, sin embargo, un costo significativo para esto:

  • Hasta 20x en listas casi idénticas de rendimiento
  • Hasta 2.5 veces en el rendimiento en listas cortas

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

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) 

Un trazador de líneas:

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

También una sola línea:

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

La diferencia entre las 3 versiones es que:

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

resultado de timeit , para Python 2.7 y (solo s1, s4, s7, s9 deben 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 

Una solución más rápida que usar set () que funciona en secuencias (no iterables) es simplemente contar el primer elemento. Esto supone que la lista no está vacía (pero es trivial de verificar y decidir cuál 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 

La forma más sencilla 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 que Python tiene una semántica perezosa).

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

Un conjunto de trabajo de comparación:

 len(set(the_list)) == 1 

El uso de set elimina todos los elementos duplicados.

Puede convertir la lista a un conjunto. Un conjunto no puede tener duplicados. Entonces, si todos los elementos en 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. 

Para lo que vale, esto apareció recientemente en la lista de correo de python-ideas . Resulta que ya hay una receta de itertools para hacer esto: 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 se desempeña muy bien y tiene algunas propiedades agradables.

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

1 En otras palabras, no puedo tomar el crédito por encontrar la solución, ni tampoco puedo tomar crédito por encontrarla .

Aquí hay dos formas simples de hacer esto

usando set ()

Al convertir la lista en un conjunto, se eliminan los elementos duplicados. Entonces, si la longitud del conjunto convertido es 1, esto implica que todos los elementos son iguales.

 len(set(input_list))==1 

Aquí hay un ejemplo

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

usando todos ()

Esto comparará (equivalencia) el primer elemento de la lista de entrada con cada otro elemento de la lista. Si todos son equivalentes, se devolverá True, de lo contrario se devolverá False.

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

Aquí hay 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 

PS Si está comprobando si la lista completa es equivalente a un cierto valor, puede sustituir el valor para input_list [0].

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 

Esta es una forma simple de hacerlo:

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

Esto es un poco más complicado, incurre en sobrecarga de llamada de función, pero la semántica se explica más claramente:

 def all_identical(seq): if not seq: # empty list is False. return False first = seq[0] return all(first == elem for elem in seq) 

Dudo que este sea el “más pythonico”, pero algo 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.

Si estás interesado en algo un poco más legible (pero, por supuesto, no tan eficiente), puedes probar:

 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 

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

Respecto a la utilización de reduce() con lambda . Aquí hay un código de trabajo que personalmente creo que es mucho mejor que algunas de las otras respuestas.

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

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

Compruebe si todos los elementos son iguales al primero.

np.allclose(array, array[0])

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

Funciona en Python 2.4, que no tiene “todos”.

Puede usar mapa y lambda

 lst = [1,1,1,1,1,1,1,1,1] print all(map(lambda x: x == lst[0], lst[1:])) 

Tu puedes hacer:

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

Es bastante molesto que Python te haga importar los operadores como operator.and_ . A partir de python3, también deberá importar functools.reduce .

(No debe usar este método porque no se romperá si encuentra valores no iguales, pero continuará examinando la lista completa. Se incluye aquí como una respuesta completa).

 lambda lst: reduce(lambda a,b:(b,b==a[0] and a[1]), lst, (lst[0], True))[1] 

El siguiente será cortocircuito corto:

 all(itertools.imap(lambda i:yourlist[i]==yourlist[i+1], xrange(len(yourlist)-1))) 

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

También hay una opción recursiva de Python pura:

  def checkEqual(lst): if len(lst)==2 : return lst[0]==lst[1] else: return lst[0]==lst[1] and checkEqual(lst[1:]) 

Sin embargo, por alguna razón, en algunos casos es dos órdenes de magnitud más lento que otras opciones. Viniendo de la mentalidad del lenguaje C, esperaba que esto fuera más rápido, ¡pero no lo es!

La otra desventaja es que hay un límite de recursión en Python que debe ajustarse en este caso. Por ejemplo usando esto .

O use el método diff de numpy:

 import numpy as np def allthesame(l): return np.all(np.diff(l)==0) 

Y para llamar:

 print(allthesame([1,1,1])) 

Salida:

 True 

O use el método diff de numpy:

 import numpy as np def allthesame(l): return np.unique(l).shape[0]<=1 

Y para llamar:

 print(allthesame([1,1,1])) 

Salida:

Cierto