Como posso comparar duas listas em python e retornar correspondências

381

Quero pegar duas listas e encontrar os valores que aparecem em ambas.

a = [1, 2, 3, 4, 5]
b = [9, 8, 7, 6, 5]

returnMatches(a, b)

retornaria [5], por exemplo.

tehryan
fonte
4
As respostas abaixo parecem erradas para mim. O que acontece se um número é repetido em qualquer lista, certamente você gostaria de saber que (?) (Por exemplo, digamos que as duas listas tenham '5' duas vezes) Qualquer solução que utilize conjuntos removerá imediatamente todos os itens repetidos e você perderá essa informação.
MH
Possível duplicata de Como encontrar a interseção da lista?
Kushan Gunasekera

Respostas:

487

Não é a mais eficiente, mas a maneira mais óbvia de fazer isso é:

>>> a = [1, 2, 3, 4, 5]
>>> b = [9, 8, 7, 6, 5]
>>> set(a) & set(b)
{5}

se a ordem for significativa, você poderá fazê-lo com compreensões de lista como esta:

>>> [i for i, j in zip(a, b) if i == j]
[5]

(funciona apenas para listas de tamanho igual, o que implica significado de ordem).

SilentGhost
fonte
15
Uma nota de cautela, a compreensão da lista não é necessariamente a opção mais rápida. Para conjuntos maiores (onde é mais provável que o desempenho seja importante), a comparação bit a bit ( &) ou set(a).intersection(b)será tão rápida ou mais rápida que a compreensão da lista.
Joshmaker
24
Outra nota de cautela: a compreensão da lista encontra os valores que aparecem nas duas posições MESMAS (isto é o que SilentGhost quis dizer com "ordem é significativa"). As soluções de interseção definidas também encontrarão correspondências em posições DIFERENTES. Estes são respostas a 2 perguntas completamente diferentes ... (pergunta do OP é ambígua a respeito de que ele está pedindo)
drevicko
Como você faz isso se suas listas são listas de listas, ou seja, a = [[0,0], [1,0]] eb = [[2,3], [0,0]]
Schneems
3
Qual seria a complexidade temporal do primeiro exemplo set(a) & set(b)?
AdjunctProfessorFalcon
Observe que isso não funciona se os dois conjuntos estiverem vazios e você espera que a comparação seja aprovada. Então mude para "(conjunto (a) e conjunto (b)) ou (não a e não b)"
Neil McGill
395

Use set.intersection () , é rápido e legível.

>>> set(a).intersection(b)
set([5])
Dennis
fonte
28
Essa resposta tem um bom desempenho algorítmico, pois apenas uma das listas (mais curta deve ser preferida) é transformada em um conjunto para pesquisa rápida e a outra lista é percorrida procurando seus itens no conjunto.
U0b34a0f6ae 7/09/09
18
bool(set(a).intersection(b))para TrueouFalse
Akshay
6
Essa resposta é mais flexível e legível, pois as pessoas podem precisar differenceou union.
Shihe Zhang #
E se eu tiver objetos como elementos da lista e desejar apenas correspondências parciais, ou seja, apenas alguns atributos tiverem que corresponder para que sejam considerados como objetos correspondentes?
CGFoX 22/03/19
Existe alguma diferença de desempenho para .intersection()vs &?
brandonbanks
106

Um teste rápido de desempenho mostrando a solução da Lutz é o melhor:

import time

def speed_test(func):
    def wrapper(*args, **kwargs):
        t1 = time.time()
        for x in xrange(5000):
            results = func(*args, **kwargs)
        t2 = time.time()
        print '%s took %0.3f ms' % (func.func_name, (t2-t1)*1000.0)
        return results
    return wrapper

@speed_test
def compare_bitwise(x, y):
    set_x = frozenset(x)
    set_y = frozenset(y)
    return set_x & set_y

@speed_test
def compare_listcomp(x, y):
    return [i for i, j in zip(x, y) if i == j]

@speed_test
def compare_intersect(x, y):
    return frozenset(x).intersection(y)

# Comparing short lists
a = [1, 2, 3, 4, 5]
b = [9, 8, 7, 6, 5]
compare_bitwise(a, b)
compare_listcomp(a, b)
compare_intersect(a, b)

# Comparing longer lists
import random
a = random.sample(xrange(100000), 10000)
b = random.sample(xrange(100000), 10000)
compare_bitwise(a, b)
compare_listcomp(a, b)
compare_intersect(a, b)

Estes são os resultados na minha máquina:

# Short list:
compare_bitwise took 10.145 ms
compare_listcomp took 11.157 ms
compare_intersect took 7.461 ms

# Long list:
compare_bitwise took 11203.709 ms
compare_listcomp took 17361.736 ms
compare_intersect took 6833.768 ms

Obviamente, qualquer teste de desempenho artificial deve ser feito com um grão de sal, mas como a set().intersection()resposta é pelo menos tão rápida quanto as outras soluções e também a mais legível, deve ser a solução padrão para esse problema comum.

Joshmaker
fonte
Set está realmente removendo repetições, portanto, no meu caso, não funcionará
rgralma 06/03
@rgralma criar um novo a setpartir de um existente listnão removerá nada do original list. Se você deseja que uma lógica especial manipule duplicatas em uma lista, acho que você precisará fazer uma nova pergunta, porque a resposta precisará ser específica de como você deseja que as duplicatas sejam manipuladas.
Joshmaker 25/03
67

Eu prefiro as respostas baseadas em conjuntos, mas aqui está uma que funciona de qualquer maneira

[x for x in a if x in b]
SingleNegationElimination
fonte
15

A maneira mais fácil de fazer isso é usar conjuntos :

>>> a = [1, 2, 3, 4, 5]
>>> b = [9, 8, 7, 6, 5]
>>> set(a) & set(b)
set([5])
Greg Hewgill
fonte
15

Atalho:

list(set(a).intersection(set(b)))
DeslocadoAussie
fonte
14
>>> s = ['a','b','c']   
>>> f = ['a','b','d','c']  
>>> ss= set(s)  
>>> fs =set(f)  
>>> print ss.intersection(fs)   
   **set(['a', 'c', 'b'])**  
>>> print ss.union(fs)        
   **set(['a', 'c', 'b', 'd'])**  
>>> print ss.union(fs)  - ss.intersection(fs)   
   **set(['d'])**
setz
fonte
11
A resposta aceita não funciona para listas que contêm seqüências de caracteres. Este faz.
Antony
12

Além disso, você pode tentar fazer isso mantendo elementos comuns em uma nova lista.

new_list = []
for element in a:
    if element in b:
        new_list.append(element)
mushfiq
fonte
5

Deseja duplicatas? Caso contrário, talvez você deva usar conjuntos:


>>> set([1, 2, 3, 4, 5]).intersection(set([9, 8, 7, 6, 5]))
set([5])
Timothy Pratley
fonte
Se você realmente deseja listas, java2s.com/Code/Python/List/Functiontointersecttwolists.htm >>> intersect ([1, 2, 3, 4, 5], [9, 8, 7, 6, 5]) [5 ]
Timothy Pratley 07/09/09
De acordo com o doc - ... exclui construções propensas a erros como Set ('abc') e 'cbs' em favor do conjunto mais legível ('abc'). Intersection ('cbs'). - docs.python.org/library/sets.html
Aaron Newton
5

outra maneira um pouco mais funcional de verificar a igualdade de lista para a lista 1 (lst1) e a lista 2 (lst2) onde os objetos têm profundidade um e que mantém a ordem:

all(i == j for i, j in zip(lst1, lst2))   
importa
fonte
4
a = [1, 2, 3, 4, 5]
b = [9, 8, 7, 6, 5]

lista =set(a)
listb =set(b)   
print listb.intersection(lista)   
returnMatches = set(['5']) #output 

print " ".join(str(return) for return in returnMatches ) # remove the set()   

 5        #final output 
Harish Verma
fonte
11
Embora esse código possa responder à pergunta, fornecer um contexto adicional sobre como e / ou por que resolve o problema melhoraria o valor a longo prazo da resposta.
Donald Duck
4

Também pode usar itertools.product.

>>> common_elements=[]
>>> for i in list(itertools.product(a,b)):
...     if i[0] == i[1]:
...         common_elements.append(i[0])
Super Nova
fonte
3

Você pode usar

def returnMatches(a,b):
       return list(set(a) & set(b))
Prabhu
fonte
3

Você pode usar:

a = [1, 3, 4, 5, 9, 6, 7, 8]
b = [1, 7, 0, 9]
same_values = set(a) & set(b)
print same_values

Resultado:

set([1, 7, 9])
Adnan Ghaffar
fonte
4
como isso é diferente da resposta aceita de mais de 6 anos atrás?
tmdavison
11
Bem, eu escrevi o detalhe completo com saída e bom para python iniciante
Adnan Ghaffar
2

Se você deseja um valor booleano:

>>> a = [1, 2, 3, 4, 5]
>>> b = [9, 8, 7, 6, 5]
>>> set(b) == set(a)  & set(b) and set(a) == set(a) & set(b)
False
>>> a = [3,1,2]
>>> b = [1,2,3]
>>> set(b) == set(a)  & set(b) and set(a) == set(a) & set(b)
True
Matheus Araujo
fonte
1

A solução a seguir funciona para qualquer ordem de itens da lista e também suporta as duas listas com comprimento diferente.

import numpy as np
def getMatches(a, b):
    matches = []
    unique_a = np.unique(a)
    unique_b = np.unique(b)
    for a in unique_a:
        for b in unique_b:
            if a == b:
                matches.append(a)
    return matches
print(getMatches([1, 2, 3, 4, 5], [9, 8, 7, 6, 5, 9])) # displays [5]
print(getMatches([1, 2, 3], [3, 4, 5, 1])) # displays [1, 3]
Hafizur Rahman
fonte
11
O Numpy tem uma função específica para isso:np.intersect1d(list1, list2)
obchardon
0

Usar o __and__método de atributo também funciona.

>>> a = [1, 2, 3, 4, 5]
>>> b = [9, 8, 7, 6, 5]
>>> set(a).__and__(set(b))
set([5])

ou simplesmente

>>> set([1, 2, 3, 4, 5]).__and__(set([9, 8, 7, 6, 5]))
set([5])
>>>    
Super Nova
fonte
0
you can | for set union and & for set intersection.
for example:

    set1={1,2,3}
    set2={3,4,5}
    print(set1&set2)
    output=3

    set1={1,2,3}
    set2={3,4,5}
    print(set1|set2)
    output=1,2,3,4,5

curly braces in the answer.
Ravi Tanwar
fonte
4
A pergunta era para lista e sem conjunto. uso do &operador no set já é a resposta por SilentGhost na resposta aceita
dWinder
0

Eu apenas usei o seguinte e funcionou para mim:

group1 = [1, 2, 3, 4, 5]
group2 = [9, 8, 7, 6, 5]

for k in group1:
    for v in group2:
        if k == v:
            print(k)

isso imprimiria 5 no seu caso. Provavelmente não é ótimo desempenho sábio embora.

LRBrady
fonte