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.


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

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


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

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.


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]

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


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

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)

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

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

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 

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

3

Você pode usar

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

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

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

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]

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

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.

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.

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.