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 containersea repetible (es decir, que no sea un generador). itemspuede 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 containery itemsson 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 containersea un conjunto, alltodaví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 cimplementación rápida de Python de set, pero el algoritmo fundamental es el mismo en ambos casos.
Si itemsya 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 containeres 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 containercomo 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 bigseqson 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 alles más rápido. ¿Qué pasa si itemstiene 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 setconstructor tiene que consumir todo el generador. Pero el comportamiento de cortocircuito de allasegura 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 containera un conjunto vale la pena, al menos si todos sus elementos son hash. Eso es porque inpara conjuntos es O (1), mientras que inpara 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, alles 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
inque 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', Truedesde'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
filterhay un generador. Debería ajustarlolistsi 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 enanyoall.Así es como lo hice:
fuente