Esto hace lo que quiere y funcionará en casi todos los casos:
>>> all(x in ['b', 'a', 'foo', 'bar'] for x in ['a', 'b'])
True
La expresión 'a','b' in ['b', 'a', 'foo', 'bar']
no funciona como se esperaba porque Python la interpreta como una tupla:
>>> 'a', 'b'
('a', 'b')
>>> 'a', 5 + 2
('a', 7)
>>> 'a', 'x' in 'xerxes'
('a', True)
Otras opciones
Hay otras formas de ejecutar esta prueba, pero no funcionarán para tantos tipos diferentes de entradas. Como señala Kabie , puede resolver este problema usando conjuntos ...
>>> set(['a', 'b']).issubset(set(['a', 'b', 'foo', 'bar']))
True
>>> {'a', 'b'} <= {'a', 'b', 'foo', 'bar'}
True
...algunas veces:
>>> {'a', ['b']} <= {'a', ['b'], 'foo', 'bar'}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
Los conjuntos solo se pueden crear con elementos hash. Pero la expresión generadora all(x in container for x in items)
puede manejar casi cualquier tipo de contenedor. El único requisito es que container
sea repetible (es decir, que no sea un generador). items
puede ser iterable en absoluto.
>>> container = [['b'], 'a', 'foo', 'bar']
>>> items = (i for i in ('a', ['b']))
>>> all(x in [['b'], 'a', 'foo', 'bar'] for x in items)
True
Pruebas de velocidad
En muchos casos, la prueba de subconjunto será más rápida que all
, pero la diferencia no es sorprendente, excepto cuando la pregunta es irrelevante porque los conjuntos no son una opción. Convertir listas en conjuntos solo con el propósito de una prueba como esta no siempre valdrá la pena. Y convertir generadores en conjuntos a veces puede ser un desperdicio increíble, lo que ralentiza los programas en muchos órdenes de magnitud.
Aquí hay algunos puntos de referencia para ilustrar. La mayor diferencia se produce cuando ambos container
y items
son relativamente pequeños. En ese caso, el enfoque de subconjunto es aproximadamente un orden de magnitud más rápido:
>>> smallset = set(range(10))
>>> smallsubset = set(range(5))
>>> %timeit smallset >= smallsubset
110 ns ± 0.702 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)
>>> %timeit all(x in smallset for x in smallsubset)
951 ns ± 11.5 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)
Esto parece una gran diferencia. Pero mientras container
sea un conjunto, all
todavía se puede utilizar perfectamente a escalas mucho mayores:
>>> bigset = set(range(100000))
>>> bigsubset = set(range(50000))
>>> %timeit bigset >= bigsubset
1.14 ms ± 13.9 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)
>>> %timeit all(x in bigset for x in bigsubset)
5.96 ms ± 37 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
El uso de pruebas de subconjuntos es aún más rápido, pero solo alrededor de 5 veces en esta escala. El aumento de velocidad se debe a la c
implementación rápida de Python de set
, pero el algoritmo fundamental es el mismo en ambos casos.
Si items
ya está almacenado en una lista por otros motivos, tendrá que convertirlos en un conjunto antes de utilizar el enfoque de prueba de subconjuntos. Luego, la aceleración se reduce a aproximadamente 2.5x:
>>> %timeit bigset >= set(bigsubseq)
2.1 ms ± 49.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
Y si su container
es una secuencia, y debe convertirse primero, entonces la aceleración es aún menor:
>>> %timeit set(bigseq) >= set(bigsubseq)
4.36 ms ± 31.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
La única vez que obtenemos resultados desastrosamente lentos es cuando salimos container
como una secuencia:
>>> %timeit all(x in bigseq for x in bigsubseq)
184 ms ± 994 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
Y, por supuesto, solo lo haremos si es necesario. Si todos los elementos bigseq
son hash, haremos esto en su lugar:
>>> %timeit bigset = set(bigseq); all(x in bigset for x in bigsubseq)
7.24 ms ± 78 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
Eso es solo 1,66 veces más rápido que la alternativa (set(bigseq) >= set(bigsubseq)
cronometrado arriba en 4,36).
Por lo tanto, las pruebas de subconjuntos son generalmente más rápidas, pero no por un margen increíble. Por otro lado, veamos cuándo all
es más rápido. ¿Qué pasa si items
tiene diez millones de valores y es probable que tenga valores que no están incluidos container
?
>>> %timeit hugeiter = (x * 10 for bss in [bigsubseq] * 2000 for x in bss); set(bigset) >= set(hugeiter)
13.1 s ± 167 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
>>> %timeit hugeiter = (x * 10 for bss in [bigsubseq] * 2000 for x in bss); all(x in bigset for x in hugeiter)
2.33 ms ± 65.2 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
En este caso, convertir el generador en un conjunto resulta un desperdicio increíble. El set
constructor tiene que consumir todo el generador. Pero el comportamiento de cortocircuito de all
asegura que solo se necesite consumir una pequeña porción del generador, por lo que es más rápido que una prueba de subconjunto en cuatro órdenes de magnitud .
Este es un ejemplo extremo, sin duda. Pero como muestra, no se puede asumir que un enfoque u otro será más rápido en todos los casos.
El resultado
La mayoría de las veces, la conversión container
a un conjunto vale la pena, al menos si todos sus elementos son hash. Eso es porque in
para conjuntos es O (1), mientras que in
para secuencias es O (n).
Por otro lado, el uso de pruebas de subconjuntos probablemente solo valga la pena a veces. Definitivamente hágalo si sus elementos de prueba ya están almacenados en un conjunto. De lo contrario, all
es solo un poco más lento y no requiere almacenamiento adicional. También se puede utilizar con grandes generadores de elementos y, en ocasiones, proporciona una aceleración masiva en ese caso.
set(['a', 'b']) <= set(['b','a','foo','bar'])
curioso : es otra forma de deletrear lo mismo y parece más "matemático".{'a', 'b'} <= {'b','a','foo','bar'}
Estoy bastante seguro de
in
que tiene una precedencia más alta que,,
por lo que su declaración se interpreta como'a', ('b' in ['b' ...])
, que luego se evalúa como'a', True
desde'b'
está en la matriz.Consulte la respuesta anterior para saber cómo hacer lo que quiere.
fuente
Si desea verificar todas sus coincidencias de entrada ,
si desea comprobar al menos una coincidencia ,
fuente
El analizador de Python evaluó esa declaración como una tupla, donde estaba el primer valor
'a'
y el segundo valor es la expresión'b' in ['b', 'a', 'foo', 'bar']
(que se evalúa comoTrue
).Sin embargo, puede escribir una función simple para hacer lo que quiera:
Y llámalo como:
fuente
La razón por la que creo que esto es mejor que la respuesta elegida es que realmente no es necesario llamar a la función 'all ()'. La lista vacía se evalúa como Falsa en declaraciones IF, la lista no vacía se evalúa como Verdadero.
Ejemplo:
fuente
Yo diría que incluso podemos omitir esos corchetes.
fuente
Ambas respuestas presentadas aquí no manejarán elementos repetidos. Por ejemplo, si está probando si [1,2,2] es una sublista de [1,2,3,4], ambos devolverán True. Puede que sea eso lo que pretendes hacer, pero solo quería aclararlo. Si desea devolver falso para [1,2,2] en [1,2,3,4], deberá ordenar ambas listas y marcar cada elemento con un índice móvil en cada lista. Solo un bucle for ligeramente más complicado.
fuente
¡Cómo puedes ser pitónico sin lambdas! .. no para ser tomado en serio .. pero esta forma también funciona:
omita la parte final si desea probar si alguno de los valores está en la matriz:
fuente
filter
hay un generador. Debería ajustarlolist
si realmente desea obtener un resultado con el que pueda probar==
o en un contexto booleano (para ver si está vacío). Es preferible utilizar una lista de comprensión o una expresión generadora enany
oall
.Así es como lo hice:
fuente