¿Cómo verificar si uno de los siguientes elementos está en una lista?


220

Estoy tratando de encontrar una manera corta de ver si alguno de los siguientes elementos está en una lista, pero mi primer intento no funciona. Además de escribir una función para lograr esto, es la forma más corta de verificar si uno de los múltiples elementos está en una lista.

>>> a = [2,3,4]
>>> print (1 or 2) in a
False
>>> print (2 or 1) in a
True

Cosa curiosa, verifiqué cómo se comporta 'y'. a = [1, 2] b = [3, 5, 2, 6, 8, 9] c = [3, 5, 6, 8, 1, 9] print( (1 and 2) in b ,(2 and 1) in b ,(1 and 2) in c ,(2 and 1) in c, sep='\n')es Verdadero Falso Falso Verdadero
Piotr Kamoda

Respuestas:


266
>>> L1 = [2,3,4]
>>> L2 = [1,2]
>>> [i for i in L1 if i in L2]
[2]


>>> S1 = set(L1)
>>> S2 = set(L2)
>>> S1.intersection(S2)
set([2])

Tanto las listas vacías como los conjuntos vacíos son falsos, por lo que puede usar el valor directamente como un valor de verdad.


66
La idea de intersección me dio esta idea. return len (set (a) .intersection (set (b)))
Deon

13
FWIW - Hice una comparación de velocidad, y la primera solución que se ofreció aquí fue el ayuno con diferencia.
jackiekazil

2
La respuesta de @ user89788 usando un generador es mucho más rápida nuevamente, porque anypuede regresar temprano tan pronto como encuentre un Truevalor, no tiene que construir la lista completa primero
Anentropic

La segunda solución / sets no funcionará si tiene duplicados en la lista (ya que los sets solo contienen uno de cada elemento). Si `L1 = [1,1,2,3] 'y' L2 = [1,2,3] ', se verá que todos los elementos se cruzan.
donrondadon

Sé que esto tiene casi 10 años, pero la primera solución no parece funcionar para mí. He sustituido los números en L2 por cadenas, y obtengo el siguiente error: TypeError: 'in <string>' requiere una cadena como operando izquierdo, no una lista
roastbeeef

227

Ah, Tobías, me ganaste. Estaba pensando en esta ligera variación en su solución:

>>> a = [1,2,3,4]
>>> b = [2,7]
>>> print(any(x in a for x in b))
True

55
Me doy cuenta de que esta es una respuesta muy antigua, pero si una lista es muy larga y la otra es corta, ¿hay un orden que produzca un rendimiento más rápido? (es decir, x in long for x in shortvs x in short for x in long)
Luke Sapan

11
@LukeSapan: Tienes razón. Ese orden se puede obtener a través de "print any (x in max (a, b, key = len) for x in min (a, b, key = len))". Esto usa x en largo para x en corto.
Nuclearman

2
Esta es la mejor respuesta porque utiliza un generador y regresará tan pronto como se encuentre una coincidencia (como han dicho otros, ¡pero no en esta respuesta!).
dotcomly

44
@Nuclearman, tenga cuidado: si las dos listas ay btienen la misma longitud, máximo y mínimo devolverá el del extremo izquierdo lista, lo que hace la any()llamada operar sobre la misma lista en ambos lados. Si necesita absolutamente la comprobación de longitud, invertir el orden de las listas en la segunda llamada: any(x in max(a, b, key=len) for x in (b, a, key=len)).
Noah Bogart

3
@NoahBogart Tienes razón y esa solución parece tan buena como cualquiera. También supongo que quisiste decir: any(x in max(a, b, key=len) for x in min(b, a, key=len))(perdí el mínimo).
Nuclearman

29

Quizás un poco más vago:

a = [1,2,3,4]
b = [2,7]

print any((True for x in a if x in b))

1
Es casi lo mismo que publiqué.
Bastien Léonard

55
@ BastienLéonard ... excepto que es mucho más rápido porque usa un generador y, por lo tanto, anypuede regresar antes, mientras que su versión tiene que construir toda la lista a partir de la comprensión antes de anypoder usarla. La respuesta de @ user89788 es ligeramente mejor porque los paréntesis dobles son innecesarios
Anentropic

17

¡Piensa en lo que el código realmente dice!

>>> (1 or 2)
1
>>> (2 or 1)
2

Eso probablemente debería explicarlo. :) Python aparentemente implementa "perezoso o", lo que no debería sorprendernos. Lo realiza algo como esto:

def or(x, y):
    if x: return x
    if y: return y
    return False

En el primer ejemplo, x == 1y y == 2. En el segundo ejemplo, es al revés. Es por eso que devuelve diferentes valores dependiendo del orden de ellos.


16
a = {2,3,4}
if {1,2} & a:
    pass

Código de la versión de golf. Considere usar un conjunto si tiene sentido hacerlo. Me parece más legible que una lista de comprensión.


12

1 línea sin listas de comprensión.

>>> any(map(lambda each: each in [2,3,4], [1,2]))
True
>>> any(map(lambda each: each in [2,3,4], [1,5]))
False
>>> any(map(lambda each: each in [2,3,4], [2,4]))
True


6

En python 3 podemos comenzar a utilizar el asterisco desempaquetado. Dadas dos listas:

bool(len({*a} & {*b}))

Editar: incorporar la sugerencia de alkanen


1
@Anthony, crea un conjunto que contiene los elementos en a, y otro conjunto que contiene los elementos en b, luego encuentra la intersección (elementos compartidos) entre esos conjuntos y any () devuelve verdadero si hay tales elementos que son verdaderos. La solución no funcionará si los únicos elementos compartidos son falsos (como el número 0). Podría ser mejor usar len () que cualquier ()
alkanen

1
@alkanen Good call
Daniel Braun

¿Por qué no utilizar la función set?
Alex78191

5

Cuando piense "comprobar para ver si a en b", piense en hashes (en este caso, conjuntos). La forma más rápida es hacer un hash de la lista que desea verificar, y luego verificar cada elemento allí.

Es por eso que la respuesta de Joe Koberg es rápida: verificar la intersección del conjunto es muy rápido.

Sin embargo, cuando no tienes muchos datos, hacer conjuntos puede ser una pérdida de tiempo. Por lo tanto, puede hacer un conjunto de la lista y simplemente verificar cada elemento:

tocheck = [1,2] # items to check
a = [2,3,4] # the list

a = set(a) # convert to set (O(len(a)))
print [i for i in tocheck if i in a] # check items (O(len(tocheck)))

Cuando el número de artículos que desea verificar es pequeño, la diferencia puede ser insignificante. Pero compruebe muchos números en una lista grande ...

pruebas:

from timeit import timeit

methods = ['''tocheck = [1,2] # items to check
a = [2,3,4] # the list
a = set(a) # convert to set (O(n))
[i for i in tocheck if i in a] # check items (O(m))''',

'''L1 = [2,3,4]
L2 = [1,2]
[i for i in L1 if i in L2]''',

'''S1 = set([2,3,4])
S2 = set([1,2])
S1.intersection(S2)''',

'''a = [1,2]
b = [2,3,4]
any(x in a for x in b)''']

for method in methods:
    print timeit(method, number=10000)

print

methods = ['''tocheck = range(200,300) # items to check
a = range(2, 10000) # the list
a = set(a) # convert to set (O(n))
[i for i in tocheck if i in a] # check items (O(m))''',

'''L1 = range(2, 10000)
L2 = range(200,300)
[i for i in L1 if i in L2]''',

'''S1 = set(range(2, 10000))
S2 = set(range(200,300))
S1.intersection(S2)''',

'''a = range(200,300)
b = range(2, 10000)
any(x in a for x in b)''']

for method in methods:
    print timeit(method, number=1000)

velocidades:

M1: 0.0170331001282 # make one set
M2: 0.0164539813995 # list comprehension
M3: 0.0286040306091 # set intersection
M4: 0.0305438041687 # any

M1: 0.49850320816 # make one set
M2: 25.2735087872 # list comprehension
M3: 0.466138124466 # set intersection
M4: 0.668627977371 # any

El método que es consistentemente rápido es hacer un conjunto (de la lista), ¡pero la intersección funciona mejor en conjuntos de datos grandes!


3

En algunos casos (p. Ej., Elementos de lista únicos), se pueden usar operaciones de conjuntos.

>>> a=[2,3,4]
>>> set(a) - set([2,3]) != set(a)
True
>>> 

O, usando set.isdisjoint () ,

>>> not set(a).isdisjoint(set([2,3]))
True
>>> not set(a).isdisjoint(set([5,6]))
False
>>> 

2

Esto lo hará en una línea.

>>> a=[2,3,4]
>>> b=[1,2]
>>> bool(sum(map(lambda x: x in b, a)))
True

No obtengo un Verdadero aquí >>> imprime a [2, 3, 4] >>> imprime b [2, 7] >>> reduce (lambda x, y: x en b, a) Falso
Deon

Sí. Tienes razón. reduce () no estaba manejando los valores booleanos como pensé que lo haría. Sin embargo, la versión revisada que escribí anteriormente funciona para ese caso.
Chris Upchurch

2

Recopilé varias de las soluciones mencionadas en otras respuestas y en comentarios, luego realicé una prueba de velocidad. not set(a).isdisjoint(b)resultó ser el más rápido, tampoco disminuyó mucho cuando el resultado fue False.

Cada una de las tres ejecuciones prueba una pequeña muestra de las posibles configuraciones de ay b. Los tiempos están en microsegundos.

Any with generator and max
        2.093 1.997 7.879
Any with generator
        0.907 0.692 2.337
Any with list
        1.294 1.452 2.137
True in list
        1.219 1.348 2.148
Set with &
        1.364 1.749 1.412
Set intersection explcit set(b)
        1.424 1.787 1.517
Set intersection implicit set(b)
        0.964 1.298 0.976
Set isdisjoint explicit set(b)
        1.062 1.094 1.241
Set isdisjoint implicit set(b)
        0.622 0.621 0.753

import timeit

def printtimes(t):
    print '{:.3f}'.format(t/10.0),

setup1 = 'a = range(10); b = range(9,15)'
setup2 = 'a = range(10); b = range(10)'
setup3 = 'a = range(10); b = range(10,20)'

print 'Any with generator and max\n\t',
printtimes(timeit.Timer('any(x in max(a,b,key=len) for x in min(b,a,key=len))',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('any(x in max(a,b,key=len) for x in min(b,a,key=len))',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('any(x in max(a,b,key=len) for x in min(b,a,key=len))',setup=setup3).timeit(10000000))
print

print 'Any with generator\n\t',
printtimes(timeit.Timer('any(i in a for i in b)',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('any(i in a for i in b)',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('any(i in a for i in b)',setup=setup3).timeit(10000000))
print

print 'Any with list\n\t',
printtimes(timeit.Timer('any([i in a for i in b])',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('any([i in a for i in b])',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('any([i in a for i in b])',setup=setup3).timeit(10000000))
print

print 'True in list\n\t',
printtimes(timeit.Timer('True in [i in a for i in b]',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('True in [i in a for i in b]',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('True in [i in a for i in b]',setup=setup3).timeit(10000000))
print

print 'Set with &\n\t',
printtimes(timeit.Timer('bool(set(a) & set(b))',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('bool(set(a) & set(b))',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('bool(set(a) & set(b))',setup=setup3).timeit(10000000))
print

print 'Set intersection explcit set(b)\n\t',
printtimes(timeit.Timer('bool(set(a).intersection(set(b)))',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('bool(set(a).intersection(set(b)))',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('bool(set(a).intersection(set(b)))',setup=setup3).timeit(10000000))
print

print 'Set intersection implicit set(b)\n\t',
printtimes(timeit.Timer('bool(set(a).intersection(b))',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('bool(set(a).intersection(b))',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('bool(set(a).intersection(b))',setup=setup3).timeit(10000000))
print

print 'Set isdisjoint explicit set(b)\n\t',
printtimes(timeit.Timer('not set(a).isdisjoint(set(b))',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('not set(a).isdisjoint(set(b))',setup=setup2).timeit(10000000))
printtimes(timeit.Timer('not set(a).isdisjoint(set(b))',setup=setup3).timeit(10000000))
print

print 'Set isdisjoint implicit set(b)\n\t',
printtimes(timeit.Timer('not set(a).isdisjoint(b)',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('not set(a).isdisjoint(b)',setup=setup1).timeit(10000000))
printtimes(timeit.Timer('not set(a).isdisjoint(b)',setup=setup3).timeit(10000000))
print

0

Tengo que decir que mi situación puede no ser lo que está buscando, pero puede proporcionar una alternativa a su pensamiento.

He intentado tanto el método set () como cualquier método () pero aún tengo problemas con la velocidad. Entonces recordé que Raymond Hettinger dijo que todo en Python es un diccionario y usa dict siempre que puedes. Entonces eso es lo que probé.

Usé un defaultdict con int para indicar resultados negativos y usé el elemento en la primera lista como la clave para la segunda lista (convertida a defaultdict). Debido a que tiene una búsqueda instantánea con dict, sabe de inmediato si ese elemento existe en el defaultdict. Sé que no siempre puedes cambiar la estructura de datos para tu segunda lista, pero si puedes hacerlo desde el principio, entonces es mucho más rápido. Es posible que deba convertir list2 (lista más grande) a un valor predeterminado, donde clave es el valor potencial que desea verificar de una lista pequeña, y el valor es 1 (acierto) o 0 (sin acierto, predeterminado).

from collections import defaultdict
already_indexed = defaultdict(int)

def check_exist(small_list, default_list):
    for item in small_list:
        if default_list[item] == 1:
            return True
    return False

if check_exist(small_list, already_indexed):
    continue
else:
    for x in small_list:
        already_indexed[x] = 1

-4

Sencillo.

_new_list = []
for item in a:
    if item in b:
        _new_list.append(item)
    else:
        pass

1
Esto no responde la pregunta. OP quiere saber si algún valor de la lista a está en la lista b.
That1Guy
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.