Resposta curta : use not set(a).isdisjoint(b), geralmente é o mais rápido.
Existem quatro maneiras comuns de testar se há duas listas ae bcompartilhar itens. A primeira opção é converter ambos em conjuntos e verificar sua interseção, como tal:
bool(set(a) & set(b))
Como os conjuntos são armazenados usando uma tabela de hash no Python, é possível pesquisá-losO(1) (consulte aqui para obter mais informações sobre a complexidade dos operadores no Python). Teoricamente, isso é, O(n+m)em média, para ne mobjetos nas listas ae b. Mas 1) ele deve primeiro criar conjuntos das listas, o que pode levar um tempo não negligenciável, e 2) supõe que as colisões de hash sejam escassas entre seus dados.
A segunda maneira de fazer isso é usar uma expressão de gerador executando iteração nas listas, como:
any(i in a for i in b)
Isso permite pesquisar no local, para que nenhuma nova memória seja alocada para variáveis intermediárias. Também se destaca na primeira descoberta. Mas o inoperador está sempre O(n)nas listas (veja aqui ).
Outra opção proposta é um híbrido para iterar através de uma das listas, converter a outra em um conjunto e testar a associação nesse conjunto, da seguinte forma:
a = set(a); any(i in a for i in b)
Uma quarta abordagem é aproveitar o isdisjoint()método dos conjuntos (congelados) (veja aqui ), por exemplo:
not set(a).isdisjoint(b)
Se os elementos pesquisados estiverem perto do início de uma matriz (por exemplo, ela é classificada), a expressão do gerador é favorecida, pois o método de interseção de conjuntos precisa alocar nova memória para as variáveis intermediárias:
from timeit import timeit
>>> timeit('bool(set(a) & set(b))', setup="a=list(range(1000));b=list(range(1000))", number=100000)
26.077727576019242
>>> timeit('any(i in a for i in b)', setup="a=list(range(1000));b=list(range(1000))", number=100000)
0.16220548999262974
Aqui está um gráfico do tempo de execução para este exemplo em função do tamanho da lista:

Observe que os dois eixos são logarítmicos. Isso representa o melhor caso para a expressão do gerador. Como pode ser visto, o isdisjoint()método é melhor para tamanhos de lista muito pequenos, enquanto a expressão do gerador é melhor para tamanhos de lista maiores.
Por outro lado, como a pesquisa começa com o início da expressão híbrida e geradora, se o elemento compartilhado estiver sistematicamente no final da matriz (ou as duas listas não compartilharem nenhum valor), as abordagens de interseção separada e definida serão então muito mais rápido que a expressão do gerador e a abordagem híbrida.
>>> timeit('any(i in a for i in b)', setup="a=list(range(1000));b=[x+998 for x in range(999,0,-1)]", number=1000))
13.739536046981812
>>> timeit('bool(set(a) & set(b))', setup="a=list(range(1000));b=[x+998 for x in range(999,0,-1)]", number=1000))
0.08102107048034668

É interessante notar que a expressão do gerador é muito mais lenta para tamanhos de lista maiores. Isso é apenas para 1000 repetições, em vez de 100000 para a figura anterior. Essa configuração também se aproxima bem quando quando nenhum elemento é compartilhado e é o melhor caso para as abordagens de interseção separada e definida.
Aqui estão duas análises usando números aleatórios (em vez de manipular a configuração para favorecer uma técnica ou outra):

Grande chance de compartilhamento: os elementos são retirados aleatoriamente [1, 2*len(a)]. Baixa chance de compartilhamento: os elementos são retirados aleatoriamente [1, 1000*len(a)].
Até agora, essa análise supunha que as duas listas eram do mesmo tamanho. No caso de duas listas de tamanhos diferentes, por exemplo, aé muito menor, isdisjoint()é sempre mais rápido:

Verifique se a alista é menor, caso contrário, o desempenho diminui. Nesta experiência, o atamanho da lista foi definido como constante 5.
Em suma:
- Se as listas são muito pequenas (<10 elementos),
not set(a).isdisjoint(b)é sempre a mais rápida.
- Se os elementos nas listas forem classificados ou tiverem uma estrutura regular da qual você possa tirar proveito, a expressão do gerador
any(i in a for i in b)será a mais rápida em tamanhos de lista grandes;
- Teste a interseção definida com
not set(a).isdisjoint(b), que é sempre mais rápida que bool(set(a) & set(b)).
- O híbrido "iterar através da lista, testar no set"
a = set(a); any(i in a for i in b)é geralmente mais lento que outros métodos.
- A expressão do gerador e o híbrido são muito mais lentos do que as outras duas abordagens quando se trata de listas sem compartilhar elementos.
Na maioria dos casos, o uso do isdisjoint()método é a melhor abordagem, pois a expressão do gerador levará muito mais tempo para ser executada, pois é muito ineficiente quando nenhum elemento é compartilhado.
len(...) > 0porquebool(set([]))produz False. E, é claro, se você mantivesse suas listas como conjuntos, você economizaria sobrecarga na criação de conjuntos.