Como verificar se um dos seguintes itens está em uma lista?


220

Estou tentando encontrar uma maneira curta de ver se algum dos itens a seguir está em uma lista, mas minha primeira tentativa não funciona. Além de escrever uma função para fazer isso, é uma maneira curta de verificar se um dos vários itens está em uma lista.

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

Engraçado, eu verifiquei como 'e' se comporta. 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')é verdadeiro falso falso verdadeiro #
Piotr Kamoda 2/16

Respostas:


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

As listas vazias e os conjuntos vazios são Falso, portanto, você pode usar o valor diretamente como um valor verdadeiro.


6
A ideia do cruzamento me deu essa ideia. return len (conjunto (a) .intersection (conjunto (b)))
Deon

13
FWIW - Fiz uma comparação de velocidade e a primeira solução oferecida aqui foi o jejum de longe.
21712

2
@ do user89788 resposta usando um gerador é muito mais rápido de novo, porque anypode voltar mais cedo, assim que encontra um Truevalor - ele não tem que construir toda a lista primeira
Anentropic

A segunda solução / conjuntos não funcionará se você tiver duplicatas na lista (pois os conjuntos contêm apenas um de cada item). Se `L1 = [1,1,2,3] 'e' L2 = [1,2,3] ', todos os itens serão cruzados.
donrondadon

Eu sei que isso tem quase 10 anos, mas a primeira solução não parece funcionar para mim. eu tenho substituído os números em L2 para cordas, e eu estou recebendo o seguinte erro: TypeError: 'em <string>' requer string como operando à esquerda, não lista
roastbeeef

227

Ah, Tobias, você me venceu. Eu estava pensando nessa pequena variação na sua solução:

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

5
Sei que essa é uma resposta muito antiga, mas se uma lista for muito longa e a outra curta, existe uma ordem que produziria um desempenho mais rápido? (ie x in long for x in shortvs x in short for x in long)
Luke Sapan

11
@LukeSapan: Você está correto. Essa ordem pode ser obtida via "imprima qualquer (x no máximo (a, b, tecla = len) para x em min (a, b, tecla = len))". Isso usa x em comprimento para x em resumo.
Nuclearman

2
Esta é a melhor resposta, pois usa um gerador e retornará assim que uma correspondência for encontrada (como outros disseram, mas não nesta resposta!).
dotcomly

4
@Nuclearman, cuidado: se as duas listas ae btêm o mesmo comprimento, máximo e mínimo irá retornar o mais à esquerda lista, o que torna a any()chamada operar sobre a mesma lista em ambos os lados. Se você absolutamente requerem a verificação de comprimento, inverter a ordem das listas na segunda chamada: any(x in max(a, b, key=len) for x in (b, a, key=len)).
Noah Bogart

3
@NoahBogart Você está correto e essa solução parece tão boa quanto qualquer outra. Eu também presumo que você quis dizer: any(x in max(a, b, key=len) for x in min(b, a, key=len))(perdeu o minuto).
Nuclearman 31/01

29

Talvez um pouco mais preguiçoso:

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

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

1
É quase o mesmo que eu postei.
Bastien Léonard

5
@ BastienLéonard ... exceto que é muito mais rápido porque usa um gerador e, portanto, anypode retornar mais cedo, enquanto sua versão precisa criar a lista inteira a partir da compreensão antes de anypoder usá-la. @ resposta de user89788 é um pouco melhor, porque os parênteses duplos são desnecessários
Anentropic

17

Pense no que o código realmente diz!

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

Isso provavelmente deve explicar isso. :) O Python aparentemente implementa "preguiçoso ou", o que não deve surpreender. Ele executa algo parecido com isto:

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

No primeiro exemplo, x == 1e y == 2. No segundo exemplo, é vice-versa. É por isso que retorna valores diferentes, dependendo da ordem deles.


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

Código versão de golfe. Considere usar um conjunto, se fizer sentido. Acho isso mais legível do que uma compreensão de lista.


12

1 linha sem compreensão de lista.

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

No python 3, podemos começar a usar o asterisco descompactado. Dadas duas listas:

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

Edit: incorporar sugestão de alkanen


1
@Anthony, ele cria um conjunto contendo os elementos em a e outro conjunto contendo os elementos em b; em seguida, encontra a interseção (elementos compartilhados) entre esses conjuntos e any () retorna true se houver algum elemento verdadeiro. A solução não funcionará se os únicos elementos compartilhados forem falsos (como o número 0). Pode ser melhor usar len () do que qualquer ()
alkanen

1
@alkanen Boa chamada
Daniel Braun

por que não usar a função set?
Alex78191

5

Quando você pensa em "verificar se a em b", pense em hashes (nesse caso, define). A maneira mais rápida é fazer o hash da lista que você deseja verificar e, em seguida, verifique cada item lá.

É por isso que a resposta de Joe Koberg é rápida: verificar a interseção do conjunto é muito rápido.

Porém, quando você não possui muitos dados, criar conjuntos pode ser uma perda de tempo. Assim, você pode fazer um conjunto da lista e apenas verificar cada item:

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

Quando o número de itens que você deseja verificar é pequeno, a diferença pode ser insignificante. Mas verifique muitos números em uma lista grande ...

testes:

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

O método que é consistentemente rápido é criar um conjunto (da lista), mas a interseção funciona melhor em grandes conjuntos de dados!


3

Em alguns casos (por exemplo, elementos de lista exclusivos), operações de conjunto podem ser usadas.

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

Ou, usando set.isdisjoint () ,

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

2

Isso fará isso em uma linha.

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

Não estou obtendo um True aqui >>> imprima a [2, 3, 4] >>> imprima b [2, 7] >>> reduza (lambda x, y: x em b, a) Falso
Deon

Sim. Você está certo. reduce () não estava lidando com valores booleanos da maneira que eu pensava. A versão revisada que escrevi acima funciona para esse caso.
21720 Chris Upchurch

2

Reuni várias das soluções mencionadas em outras respostas e comentários e, em seguida, executei um teste de velocidade. not set(a).isdisjoint(b)acabou sendo o mais rápido, também não diminuiu muito quando o resultado foiFalse .

Cada uma das três execuções testa uma pequena amostra das configurações possíveis de ae b. Os horários estão em microssegundos.

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

Devo dizer que minha situação pode não ser o que você está procurando, mas pode fornecer uma alternativa ao seu pensamento.

Eu tentei o método set () e any (), mas ainda tenho problemas com a velocidade. Então, lembrei-me de Raymond Hettinger disse que tudo em python é um dicionário e use dict sempre que puder. Então foi isso que eu tentei.

Usei um defaultdict com int para indicar resultados negativos e usei o item na primeira lista como chave da segunda lista (convertida em defaultdict). Como você tem uma pesquisa instantânea com o dict, você sabe imediatamente se esse item existe no padrão. Sei que nem sempre é possível alterar a estrutura de dados para sua segunda lista, mas se você puder desde o início, será muito mais rápido. Pode ser necessário converter list2 (lista maior) em um padrão, onde key é o valor potencial que você deseja verificar na lista pequena e o valor é 1 (ocorrência) ou 0 (sem ocorrência, padrão).

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

Simples.

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

1
Isso não responde à pergunta. O OP deseja saber se algum valor da lista a está na lista b.
That1Guy
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.