Necesito la siguiente función:
Entrada : alist
Salida :
True
si todos los elementos en la lista de entrada se evalúan como iguales entre sí utilizando el operador de igualdad estándar;False
de otra manera.
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 pitónica de hacer eso.
La falta de función de cortocircuito solo perjudica a una entrada larga (más de ~ 50 elementos) que tienen elementos desiguales desde el principio. Si esto ocurre con la suficiente frecuencia (la frecuencia depende de la duración de las listas), se requiere un cortocircuito. El mejor algoritmo de cortocircuito parece ser @KennyTM checkEqual1
. Sin embargo, paga un costo significativo por esto:
- Hasta 20 veces en listas casi idénticas de rendimiento
- hasta 2.5x en rendimiento en listas cortas
Si las entradas largas con elementos desiguales tempranos no suceden (o suceden con suficiente frecuencia), no se requiere un cortocircuito. Entonces, con mucho, el más rápido es la solución @Ivo van der Wijk.
a == b
o idéntico como ena is b
?functools.reduce(operator.eq, a)
no se haya sugerido.Respuestas:
Método general:
Un trazador de líneas:
También una línea:
La diferencia entre las 3 versiones es que:
checkEqual2
el contenido debe ser hashable.checkEqual1
ycheckEqual2
puede usar cualquier iterador, perocheckEqual3
debe tomar una secuencia de entrada, típicamente contenedores concretos como una lista o tupla.checkEqual1
se detiene tan pronto como se encuentra una diferencia.checkEqual1
contiene más código Python, es menos eficiente cuando muchos de los elementos son iguales al principio.checkEqual2
ycheckEqual3
siempre realiza operaciones de copiado O (N), tomarán más tiempo si la mayoría de su entrada devuelve False.checkEqual2
ycheckEqual3
es más difícil adaptar la comparación dea == b
aa is b
.timeit
resultado, para Python 2.7 y (solo s1, s4, s7, s9 deberían devolver True)obtenemos
Nota:
fuente
obj.__eq__
cuándolhs is rhs
y optimizaciones fuera de orden para permitir listas ordenadas de cortocircuito más rápidamente.itertools
receta que agregué como respuesta. Podría valer la pena incluir eso en su matriz de tiempo :-).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 verificarla y decidir cuál es el resultado en una lista vacía)
Algunos puntos de referencia simples:
fuente
x.count(next(x)) == len(x)
para que funcione para cualquier contenedor x? Ahh ... nm, acabo de ver que .count solo está disponible para secuencias ... ¿Por qué no está implementado para otros contenedores integrados? ¿Cuenta dentro de un diccionario inherentemente menos significativo que dentro de una lista?count
no está implementado para iterables, no por quélen
no está disponible para iteradores. La respuesta es probablemente que es solo un descuido. Pero es irrelevante para nosotros porque el valor predeterminado.count()
para las secuencias es muy lento (Python puro). La razón por la que su solución es tan rápida es que se basa en el C implementadocount
provisto porlist
. Por lo tanto, supongo que lo que ocurra para implementar elcount
método en C se beneficiará de su enfoque.La forma más simple y elegante es la siguiente:
(¡Sí, esto incluso funciona con la lista vacía! Esto se debe a que este es uno de los pocos casos en que Python tiene una semántica perezosa).
En cuanto al rendimiento, esto fallará lo antes posible, por lo que es asintóticamente óptimo.
fuente
checkEqual1
. No estoy seguro de por qué.first=myList[0]
all(x==first for x in myList)
, tal vezfirst=myList[0]
arrojará unaIndexError
lista vacía, por lo que los comentaristas que estaban hablando de esa optimización que mencioné tendrán que lidiar con el caso de una lista vacía. Sin embargo, el original está bien (x==myList[0]
está bien dentro delall
porque nunca se evalúa si la lista está vacía).Un trabajo de comparación establecido:
El uso
set
elimina todos los elementos duplicados.fuente
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.
fuente
len(set(input_list)) == 1
?Por lo que vale, esto apareció recientemente en la lista de correo de ideas de python . Resulta que ya hay una receta de itertools para hacer esto: 1
Supuestamente funciona muy bien y tiene algunas buenas propiedades.
1 En otras palabras, no puedo tomar el crédito por encontrar la solución, ni puedo tomar el crédito por encontrarla .
fuente
return next(g, f := next(g, g)) == f
(desde py3.8, por supuesto)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, entonces esto implica que todos los elementos son iguales.
Aquí hay un ejemplo
usando all ()
Esto comparará (equivalencia) el primer elemento de la lista de entrada con cualquier otro elemento de la lista. Si todos son equivalentes, se devolverá True, de lo contrario se devolverá False.
Aquí hay un ejemplo
PD Si está verificando si toda la lista es equivalente a un cierto valor, puede suplantar el valor en input_list [0].
fuente
len(set(a))
en una lista de 10,000,000 de elementos tomó 0.09 s mientras que el desempeñoall
tomó 0.9 s (10 veces más).Esta es otra opción, más rápida que
len(set(x))==1
para listas largas (usa cortocircuito)fuente
Esta es una manera simple de hacerlo:
Esto es un poco más complicado, incurre en una sobrecarga de llamadas de función, pero la semántica se explica más claramente:
fuente
for elem in mylist[1:]
. Sin embargo, dudo que mejore mucho la velocidad, ya que supongoelem[0] is elem[0]
que el intérprete probablemente pueda hacer esa comparación muy rápidamente.Compruebe si todos los elementos son iguales al primero.
np.allclose(array, array[0])
fuente
Dudo que este sea el "más pitónico", pero algo así como:
Haría el truco.
fuente
for
bucle se puede hacer más pitónicoif any(item != list[0] for item in list[1:]): return False
, con exactamente la misma semántica.Si está interesado en algo un poco más legible (pero, por supuesto, no tan eficiente), puede probar:
fuente
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 en la lista no son idénticos.
fuente
En cuanto a usar
reduce()
conlambda
. Aquí hay un código de trabajo que personalmente creo que es mucho mejor que algunas de las otras respuestas.Devuelve una tupla donde el primer valor es el booleano si todos los elementos son iguales o no.
fuente
[1, 2, 2]
): no tiene en cuenta el valor booleano anterior. Esto se puede solucionar reemplazandox[1] == y
conx[0] and x[1] == y
.Lo haría:
como
any
deja de buscar el iterable tan pronto como encuentra unaTrue
condición.fuente
all()
, ¿por qué no usarall(x == seq[0] for x in seq)
? parece más pitónico y debería realizar lo mismofuente
Funciona en Python 2.4, que no tiene "todo".
fuente
for k in j: break
es equivalente anext(j)
. También podría haberlo hechodef allTheSame(x): return len(list(itertools.groupby(x))<2)
si no le importara la eficiencia.Puede usar mapa y lambda
fuente
O utilice el
diff
método de numpy:Y para llamar:
Salida:
fuente
not np.any(np.diff(l))
podría ser un poco más rápido.O use el método diff de numpy:
Y para llamar:
Salida:
Cierto
fuente
Tu puedes hacer:
Es bastante molesto que Python te haga importar los operadores como
operator.and_
. A partir de python3, también deberá importarfunctools.reduce
.(No debe usar este método porque no se romperá si encuentra valores no iguales, pero continuará examinando la lista completa. Solo se incluye aquí como una respuesta para completar).
fuente
El siguiente cortocircuitará:
fuente
reduce(lambda a,b:a==b, [2,2,2])
rendimientosFalse
... LoCambia la lista a un conjunto. Entonces, si el tamaño del conjunto es solo 1, deben haber sido los mismos.
fuente
También hay una opción recursiva de Python pura:
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 recurrencia en Python que debe ajustarse en este caso. Por ejemplo usando esto .
fuente
Puede utilizar
.nunique()
para encontrar el número de elementos únicos en una lista.fuente
puedes usar
set
. Hará un conjunto y eliminará elementos repetitivos. Luego verifique que no tenga más de 1 elemento.Ejemplo:
fuente