Comparação de elementos comuns entre 2 listas

143
def common_elements(list1, list2):
    """
    Return a list containing the elements which are in both list1 and list2

    >>> common_elements([1,2,3,4,5,6], [3,5,7,9])
    [3, 5]
    >>> common_elements(['this','this','n','that'],['this','not','that','that'])
    ['this', 'that']
    """
    for element in list1:
        if element in list2:
            return list(element)

Entendi isso até agora, mas não consigo fazê-lo funcionar!

Alguma ideia?

Daniel
fonte
1
Olá, você pode adicionar alguns detalhes sobre como planeja usar o código? Se isso é para concluir uma tarefa, pode ser melhor escolher uma solução que encapsule a maneira "Pythonic". No entanto, se a eficiência é sua preocupação, é improvável que o caminho "pitônico" seja a solução mais eficiente. O aconselhamento sobre esses detalhes ajudará as soluções a resolver seu problema.
Matt C

Respostas:

278
>>> list1 = [1,2,3,4,5,6]
>>> list2 = [3, 5, 7, 9]
>>> list(set(list1).intersection(list2))
[3, 5]
SilentGhost
fonte
1
+1 mas pessoalmente eu tinha frozenset usada como é imutável e assim pode ser usado como chave do dicionário etc
zebrabox
19
Isso retornará os elementos / unique / common, mas não quaisquer elementos repetidos que possam existir.
Dologan
@SilentGhost. Como obter o número de elementos correspondentes da lista dois. Nesse caso, é 2.
Poka
@Poka len (list (set (list1) .intersection (list2))))
Dharmanshu Kamra
2
PARA SUA INFORMAÇÃO. Definitivamente, isso é mais rápido que a solução proposta por Tamás, mas para o caso de uso que eu estava analisando quando acabei nesta página, era importante preservar a ordem original dos elementos para os elementos pós-filtrados. Esse método perde a ordem, enquanto o método de compreensão da lista preserva a ordem. Importante se alguém precisar considerar isso. Obrigado.
agftrading
41

Você também pode usar conjuntos e obter os pontos comuns em uma linha: subtraia o conjunto que contém as diferenças de um dos conjuntos.

A = [1,2,3,4]
B = [2,4,7,8]
commonalities = set(A) - (set(A) - set(B))
BeyondRubicon
fonte
4
Isso converte A para definir duas vezes, desnecessariamente desnecessário.
Wim
36

As soluções sugeridas por S. Marcos e SilentGhost geralmente dizer-lhe como ele deve ser feito de uma forma Pythonic, mas eu achei que você também pode se beneficiar de saber por que sua solução não funciona. O problema é que, assim que você encontrar o primeiro elemento comum nas duas listas, retornará apenas esse elemento único. Sua solução pode ser corrigida criando uma resultlista e coletando os elementos comuns nessa lista:

def common_elements(list1, list2):
    result = []
    for element in list1:
        if element in list2:
            result.append(element)
    return result

Uma versão ainda mais curta usando a compreensão da lista:

def common_elements(list1, list2):
    return [element for element in list1 if element in list2]

No entanto, como eu disse, essa é uma maneira muito ineficiente de fazer isso - os tipos de conjuntos internos do Python são muito mais eficientes à medida que são implementados em C internamente.

Tamás
fonte
1
Ótimo para ambas as propostas
dlewin
1
NOTA: Os métodos acima funcionarão apenas para listas de tamanhos iguais. Se você estiver trabalhando com listas de tamanhos desiguais, como eu, precisará avaliar a ordem com base em len () antes de chamar a função: list1 = [2,2,2], list2 [2,3] -> [2,2,2] lista1 = [2,3], lista2 [2,2,2] -> [2]
redthumb 30/09/16
29

use interseções de conjunto, conjunto (lista1) e conjunto (lista2)

>>> def common_elements(list1, list2):
...     return list(set(list1) & set(list2))
...
>>>
>>> common_elements([1,2,3,4,5,6], [3,5,7,9])
[3, 5]
>>>
>>> common_elements(['this','this','n','that'],['this','not','that','that'])
['this', 'that']
>>>
>>>

Observe que a lista de resultados pode ter uma ordem diferente da lista original.

VOCÊS
fonte
Obrigado pela ajuda. Entenda onde eu errei e no que trabalhar da próxima vez. :)
Daniel
5
ótima solução. Existe também uma maneira de preservar a ordem com isso?
Tarrasch
14

você pode usar uma compreensão simples da lista:

x=[1,2,3,4]
y=[3,4,5]
common = [i for i in x if i in y]
common: [3,4]
Mahdi Ghelichi
fonte
9

Set é outra maneira de resolver isso

a = [3,2,4]
b = [2,3,5]
set(a)&set(b)
{2, 3}
nEO
fonte
9

list1 = [1,2,3,4,5,6] list2 = [3,5,7,9]

Eu sei que três maneiras podem resolver isso, é claro, poderia haver mais.

1-

common_elements = [e for e in list1 if e in list2]

2-

import numpy as np
common_elements = np.intersect1d(list1, list2)

3-

common_elements = set(list1).intersection(list2)

A terceira maneira é a mais rápida, pois os Sets são implementados usando tabelas de hash.

Mahmoud Reda
fonte
8

As respostas anteriores trabalham para encontrar os elementos comuns exclusivos, mas falham em levar em conta itens repetidos nas listas. Se você deseja que os elementos comuns apareçam no mesmo número que eles são encontrados em comum nas listas, você pode usar a seguinte linha:

l2, common = l2[:], [ e for e in l1 if e in l2 and (l2.pop(l2.index(e)) or True)]

A or Truepeça só é necessária se você espera que algum elemento avalie False.

Dologan
fonte
Solução impressionante, parece o mais completo, se um pouco concisa
Hendeca
Essa deve ser a resposta que deveria ter sido selecionada! Suponho que também funcione para listas desiguais. Além disso, a maioria das soluções usa o setque não é estável (ou seja, o pedido é perdido).
lifebalance
7

Comparei cada método mencionado em cada resposta. Neste momento, uso o python 3.6.3 para esta implementação. Este é o código que eu usei:

import time
import random
from decimal import Decimal


def method1():
    common_elements = [x for x in li1_temp if x in li2_temp]
     print(len(common_elements))


def method2():
    common_elements = (x for x in li1_temp if x in li2_temp)
    print(len(list(common_elements)))


def method3():
    common_elements = set(li1_temp) & set(li2_temp)
    print(len(common_elements))


def method4():
    common_elements = set(li1_temp).intersection(li2_temp)
    print(len(common_elements))


if __name__ == "__main__":
    li1 = []
    li2 = []
    for i in range(100000):
        li1.append(random.randint(0, 10000))
        li2.append(random.randint(0, 10000))

    li1_temp = list(set(li1))
    li2_temp = list(set(li2))

    methods = [method1, method2, method3, method4]
    for m in methods:
        start = time.perf_counter()
        m()
        end = time.perf_counter()
        print(Decimal((end - start)))

Se você executar esse código, poderá ver que, se você usar lista ou gerador (se você iterar sobre um gerador, não apenas usá-lo. Fiz isso quando forcei o gerador a imprimir o comprimento dele), você obtém quase o mesmo desempenho. Mas se você usar o conjunto, obterá um desempenho muito melhor. Além disso, se você usar o método de interseção, obterá um desempenho um pouco melhor. o resultado de cada método no meu computador está listado abaixo:

  1. method1: 0.8150673999999999974619413478649221360683441
  2. method2: 0.8329545000000001531148541289439890533685684
  3. method3: 0.0016547000000000089414697868051007390022277
  4. method4: 0.0010262999999999244948867271887138485908508
Saber Solooki
fonte
5

esta é a minha proposta, acho que é mais fácil com conjuntos do que com um loop for

def unique_common_items(list1, list2):
   # Produce the set of *unique* common items in two lists.
   return list(set(list1) & set(list2))
Elasri
fonte
2

Por que não usar list comprehension ?

Solução de meia linha:

common_elements = [x for x in list1 if x in list2]
seralouk
fonte
0

1) Método1: salvar lista1 é dicionário e, em seguida, iterar cada elem na lista2

def findarrayhash(a,b):
    h1={k:1 for k in a}
    for val in b:
        if val in h1:
            print("common found",val)
            del h1[val]
        else:
            print("different found",val)
    for key in h1.iterkeys():
        print ("different found",key)

Localizando elementos comuns e diferentes:

2) Method2 usando set

def findarrayset(a,b):
    common = set(a)&set(b)
    diff=set(a)^set(b)
    print list(common)
    print list(diff) 
JS
fonte
-1

Use um gerador:

common = (x for x in list1 if x in list2)

A vantagem aqui é que isso retornará em tempo constante (quase instantâneo), mesmo ao usar listas enormes ou outros iteráveis.

Por exemplo,

list1 =  list(range(0,10000000))
list2=list(range(1000,20000000))
common = (x for x in list1 if x in list2)

Todas as outras respostas aqui levarão muito tempo com esses valores para list1 e list2.

Você pode iterar a resposta com

for i in common: print(i)

Ou converta-o em uma lista com

list(i)
cowlinator
fonte
Isso não produz uma resposta. O resultado é um gerador e não a lista de elementos comuns.
josiekre
1
Correto, ele cria um gerador, que é uma resposta. A questão era obter de alguma forma os elementos comuns das 2 listas, o que esse gerador faz. Simplesmente iterar o gerador assim: for i in common: print(i). Geradores são iteráveis ​​que são freqüentemente usados ​​no lugar de outros iteráveis, como listas.
cowlinator