Comment vérifier si l'un des éléments suivants figure dans une liste?

220

J'essaie de trouver un moyen rapide de voir si l'un des éléments suivants figure dans une liste, mais ma première tentative ne fonctionne pas. Outre l'écriture d'une fonction pour y parvenir, il existe un moyen court et simple de vérifier si l'un des éléments multiples est dans une liste.

>>> a = [2,3,4]
>>> print (1 or 2) in a
False
>>> print (2 or 1) in a
True
Deon
la source
Chose drôle, j'ai vérifié comment «et» se comporte. 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')est vrai faux faux vrai
Piotr Kamoda

Réponses:

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])

Les listes vides et les ensembles vides sont faux, vous pouvez donc utiliser la valeur directement comme valeur de vérité.

Joe Koberg
la source
6
L'idée d'intersection m'a donné cette idée. return len (set (a) .intersection (set (b)))
Deon
13
FWIW - J'ai fait une comparaison de vitesse, et la toute première solution proposée ici était de loin le jeûne.
jackiekazil
2
La réponse de @ user89788 à l'aide d'un générateur est de nouveau beaucoup plus rapide, car elle anypeut revenir tôt dès qu'elle trouve une Truevaleur - elle n'a pas besoin de construire d'abord la liste entière
Anentropic
La solution second / sets ne fonctionnera pas si vous avez des doublons dans la liste (car les sets ne contiennent qu'un seul de chaque élément). Si «L1 = [1,1,2,3]» et «L2 = [1,2,3]», tous les éléments se croiseront.
donrondadon
je sais que cela a presque 10 ans, mais la première solution ne semble pas fonctionner pour moi. j'ai substitué les nombres dans L2 aux chaînes, et j'obtiens l'erreur suivante: TypeError: 'in <string>' requiert une chaîne comme opérande gauche, pas une liste
roastbeeef
227

Ah, Tobias, tu m'as battu. Je pensais à cette légère variation de votre solution:

>>> a = [1,2,3,4]
>>> b = [2,7]
>>> print(any(x in a for x in b))
True
ojdo
la source
5
Je me rends compte que c'est une réponse très ancienne, mais si une liste est très longue et l'autre courte, y a-t-il une commande qui donnerait des performances plus rapides? (ie, x in long for x in shortvs x in short for x in long)
Luke Sapan
11
@LukeSapan: Vous avez raison. Cet ordre peut être obtenu via "print any (x in max (a, b, key = len) for x in min (a, b, key = len))". Cela utilise x en long pour x en bref.
Nuclearman
2
C'est la meilleure réponse car elle utilise un générateur et reviendra dès qu'une correspondance sera trouvée (comme d'autres l'ont dit, mais pas sur cette réponse!).
dotcomly
4
@Nuclearman, attention: si les deux listes a et bsont de même longueur, max et min liste la plus à gauche, ce qui fera que l' any()appel fonctionnera sur la même liste des deux côtés. Si vous avez besoin absolument vérifier la longueur, inverser l'ordre des listes dans le deuxième appel: any(x in max(a, b, key=len) for x in (b, a, key=len)).
Noah Bogart
3
@NoahBogart Vous avez raison et cette solution semble aussi bonne que n'importe quelle autre. Je suppose aussi que vous vouliez dire: any(x in max(a, b, key=len) for x in min(b, a, key=len))(raté le min).
Nuclearman
29

Peut-être un peu plus paresseux:

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

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

la source
1
C'est presque le même que celui que j'ai publié.
Bastien Léonard
5
@ BastienLéonard ... sauf qu'il est beaucoup plus rapide car il utilise un générateur et anypeut donc revenir tôt, alors que votre version doit construire toute la liste à partir de la compréhension avant de anypouvoir l'utiliser. La réponse de @ user89788 est légèrement meilleure car les doubles parenthèses ne sont pas nécessaires
Anentropic
17

Pensez à ce que dit réellement le code!

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

Cela devrait probablement l'expliquer. :) Python implémente apparemment "paresseux ou", ce qui ne devrait pas surprendre. Il exécute quelque chose comme ceci:

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

Dans le premier exemple, x == 1et y == 2. Dans le deuxième exemple, c'est l'inverse. C'est pourquoi il renvoie des valeurs différentes en fonction de leur ordre.

Deniz Dogan
la source
16
a = {2,3,4}
if {1,2} & a:
    pass

Version golf code. Envisagez d'utiliser un ensemble s'il est logique de le faire. Je trouve cela plus lisible qu'une compréhension de liste.

00500005
la source
12

1 ligne sans liste de compréhension.

>>> 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
Himel Das
la source
7

Le mieux que j'ai pu trouver:

any([True for e in (1, 2) if e in a])
Bastien Léonard
la source
6

En python 3, nous pouvons commencer à utiliser l'astérisque décompresser. Étant donné deux listes:

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

Edit: incorporez la suggestion d'alcanen

Daniel Braun
la source
1
@Anthony, il crée un ensemble contenant les éléments dans a et un autre ensemble contenant les éléments dans b, puis il trouve l'intersection (éléments partagés) entre ces ensembles et any () renvoie true s'il existe de tels éléments qui sont véridiques. La solution ne fonctionnera pas si les seuls éléments partagés sont faux (comme le nombre 0). Il pourrait être préférable d'utiliser len () que n'importe quel autre ()
alkanen
1
@alkanen Bon appel
Daniel Braun
pourquoi ne pas utiliser la fonction set?
Alex78191
5

Lorsque vous pensez "vérifier si a in b", pensez à des hachages (dans ce cas, des ensembles). Le moyen le plus rapide consiste à hacher la liste que vous souhaitez vérifier, puis à y archiver chaque élément.

C'est pourquoi la réponse de Joe Koberg est rapide: la vérification de l'intersection des ensembles est très rapide.

Cependant, lorsque vous n'avez pas beaucoup de données, la création d'ensembles peut être une perte de temps. Ainsi, vous pouvez faire un ensemble de la liste et vérifier simplement chaque élément:

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

Lorsque le nombre d'articles que vous souhaitez vérifier est petit, la différence peut être négligeable. Mais vérifiez beaucoup de chiffres par rapport à une grande liste ...

tests:

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)

vitesses:

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

La méthode qui est toujours rapide est de faire un ensemble (de la liste), mais l'intersection fonctionne le mieux sur les grands ensembles de données!

dantiston
la source
3

Dans certains cas (par exemple, des éléments de liste uniques), les opérations de définition peuvent être utilisées.

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

Ou, en utilisant set.isdisjoint () ,

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

Cela le fera en une seule ligne.

>>> a=[2,3,4]
>>> b=[1,2]
>>> bool(sum(map(lambda x: x in b, a)))
True
Chris Upchurch
la source
Je n'obtiens pas de Vrai ici >>> imprimer un [2, 3, 4] >>> imprimer b [2, 7] >>> réduire (lambda x, y: x en b, a) Faux
Deon
Oui. Vous avez raison. Reduce () ne gérait pas tout à fait les valeurs booléennes comme je le pensais. La version révisée que j'ai écrite ci-dessus fonctionne cependant pour ce cas.
Chris Upchurch
2

J'ai rassemblé plusieurs des solutions mentionnées dans d'autres réponses et dans des commentaires, puis j'ai effectué un test de vitesse. not set(a).isdisjoint(b)s'est avéré être le plus rapide, il n'a pas non plus beaucoup ralenti lorsque le résultat a été False.

Chacune des trois exécutions teste un petit échantillon des configurations possibles de aet b. Les temps sont en microsecondes.

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
chaussettes à mâcher
la source
0

Je dois dire que ma situation n'est peut-être pas celle que vous recherchez, mais elle peut fournir une alternative à votre réflexion.

J'ai essayé la méthode set () et any () mais j'ai toujours des problèmes de vitesse. Je me suis donc souvenu que Raymond Hettinger avait dit que tout en python est un dictionnaire et utilisez dict quand vous le pouvez. Voilà donc ce que j'ai essayé.

J'ai utilisé un defaultdict avec int pour indiquer des résultats négatifs et j'ai utilisé l'élément dans la première liste comme clé pour la deuxième liste (convertie en defaultdict). Parce que vous avez une recherche instantanée avec dict, vous savez immédiatement si cet élément existe dans le defaultdict. Je sais que vous ne changez pas toujours la structure des données pour votre deuxième liste, mais si vous le pouvez dès le départ, alors c'est beaucoup plus rapide. Vous devrez peut-être convertir list2 (liste plus grande) en un defaultdict, où clé est la valeur potentielle que vous souhaitez vérifier à partir d'une petite liste, et la valeur est soit 1 (hit) ou 0 (aucun hit, par défaut).

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
yangliu2
la source
-4

Facile.

_new_list = []
for item in a:
    if item in b:
        _new_list.append(item)
    else:
        pass
PyGuy
la source
1
Cela ne répond pas à la question. OP veut savoir si une valeur de la liste a est dans la liste b.
That1Guy