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?


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]

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

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.


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.


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]

9

Set é outra maneira de resolver isso

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

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.


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.


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

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

2

Por que não usar list comprehension ?

Solução de meia linha:

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

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) 

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

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