Confronto di elementi comuni tra 2 elenchi


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)

Fin qui, ma non riesco a farlo funzionare!

Qualche idea?


1
Ciao, potresti aggiungere qualche dettaglio su come pensi di utilizzare il codice? Se questo è per completare un compito, potrebbe essere meglio scegliere una soluzione che incapsuli il modo "Pythonic". Tuttavia, se l'efficienza è la tua preoccupazione, è improbabile che la via "Pythonic" sia la soluzione più efficiente. Avvisarci su questi dettagli aiuterà le soluzioni a mirare a risolvere il problema.
Matt C,

Risposte:


278
>>> list1 = [1,2,3,4,5,6]
>>> list2 = [3, 5, 7, 9]
>>> list(set(list1).intersection(list2))
[3, 5]

1
+1 ma personalmente avevo usato frozenset in quanto immutabile e quindi può essere usato come chiave del dizionario ecc.
zebrabox

19
Ciò restituirà gli elementi / unique / common, ma non eventuali elementi ripetuti che possono esistere.
Dologan,

@SilentGhost. Come ottenere il numero di elementi corrispondenti da due elenchi. In questo caso sono le 2.
Poka,

@Poka len (list (set (list1) .intersection (list2)))
Dharmanshu Kamra

2
FYI. Questo è decisamente più veloce, rispetto alla soluzione proposta da Tamás, ma per il caso d'uso che stavo guardando quando sono finito su questa pagina, era importante preservare l'ordine originale degli elementi per gli elementi post-filtrati. Questo metodo perde l'ordine, mentre il metodo di comprensione dell'elenco preserva l'ordine. Importante se qualcuno deve considerare questo. Grazie.
Agftrading

41

Puoi anche usare i set e ottenere i punti comuni in una riga: sottrarre il set contenente le differenze da uno dei set.

A = [1,2,3,4]
B = [2,4,7,8]
commonalities = set(A) - (set(A) - set(B))

4
Questo converte A per impostare due volte, inutilmente dispendioso.
mercoledì

36

Le soluzioni suggerite da S. Marco e SilentGhost generalmente ti dicono come dovrebbe essere fatto in un modo Pythonic, ma ho pensato che si potrebbe anche beneficiare di sapere perché la soluzione non funziona. Il problema è che non appena trovi il primo elemento comune nelle due liste, restituisci solo quel singolo elemento. La soluzione potrebbe essere risolta creando un resultelenco e raccogliendo gli elementi comuni in tale elenco:

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

Una versione ancora più breve usando la comprensione dell'elenco:

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

Tuttavia, come ho detto, questo è un modo molto inefficiente per farlo - i tipi di set incorporati di Python sono molto più efficienti in quanto implementati in C internamente.


1
Ottimo per entrambe le proposte
dlewin

1
NOTA: i metodi sopra funzionano solo per elenchi di dimensioni uguali. Se lavori con elenchi di dimensioni diverse, come lo sono io, dovrai valutare l'ordine in base a len () prima di chiamare la funzione: list1 = [2,2,2], list2 [2,3] -> [2,2,2] list1 = [2,3], list2 [2,2,2] -> [2]
redthumb

29

usa imposta intersezioni, imposta (elenco1) e imposta (elenco2)

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

Si noti che l'elenco dei risultati potrebbe essere di ordine diverso con l'elenco originale.


Grazie per l'aiuto. Comprendi dove ho sbagliato e su cosa lavorare la prossima volta. :)
Daniel,

5
ottima soluzione. c'è anche un modo per preservare l'ordine con questo?
Tarrasch,

14

puoi usare una semplice comprensione dell'elenco:

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

9

Il set è un altro modo per risolverlo

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]

So che 3 modi possono risolverlo, ovviamente, potrebbero essercene altri.

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)

Il terzo modo è il più veloce perché i set sono implementati usando le tabelle hash.


8

Le risposte precedenti funzionano tutte per trovare gli elementi comuni univoci, ma non tengono conto degli elementi ripetuti negli elenchi. Se si desidera che gli elementi comuni appaiano nello stesso numero in cui si trovano in comune negli elenchi, è possibile utilizzare la seguente riga singola:

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

La or Trueparte è necessaria solo se si prevede di valutare elementi False.


Soluzione eccezionale, sembra la più completa, anche se un po '
concisa

Questa dovrebbe essere la risposta che avrebbe dovuto essere selezionata! Presumo che funzioni anche per elenchi disuguali. Inoltre, la maggior parte delle soluzioni utilizza setche non è stabile (ovvero l'ordine viene perso).
lifebalance

7

Ho confrontato ciascuno dei metodi menzionati da ciascuna risposta. In questo momento uso python 3.6.3 per questa implementazione. Questo è il codice che ho usato:

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 esegui questo codice puoi vedere che se usi la lista o il generatore (se esegui l'iterazione sul generatore, non solo lo usi. L'ho fatto quando ho costretto il generatore a stamparne la lunghezza), ottieni quasi le stesse prestazioni. Ma se usi set ottieni prestazioni molto migliori. Inoltre, se usi il metodo di intersezione, otterrai prestazioni leggermente migliori. il risultato di ciascun metodo nel mio computer è elencato di seguito:

  1. method1: 0.8150673999999999974619413478649221360683441
  2. method2: 0.8329545000000001531148541289439890533685684
  3. method3: 0.0016547000000000089414697868051007390022277
  4. method4: 0.0010262999999999244948867271887138485908508

5

questa è la mia proposta, penso che sia più facile con set che con un ciclo for

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

2

Perché non usare list comprehension ?

Soluzione mezza linea:

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

0

1) Metodo1 salvando la lista1 è il dizionario e quindi ripetendo ogni elemento in 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)

Trovare elementi comuni e diversi:

2) Metodo2 usando set

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

-1

Usa un generatore:

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

Il vantaggio qui è che questo tornerà in tempo costante (quasi istantaneo) anche quando si usano elenchi enormi o altri enormi iterabili.

Per esempio,

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

Tutte le altre risposte qui impiegheranno molto tempo con questi valori per list1 e list2.

È quindi possibile iterare la risposta con

for i in common: print(i)

O convertilo in un elenco con

list(i)

Questo non produce una risposta. Il risultato è un generatore anziché l'elenco di elementi comuni.
josiekre,

1
Corretto, crea un generatore, che è una risposta. La domanda era in qualche modo ottenere gli elementi comuni delle 2 liste, cosa che fa questo generatore. Basta scorrere il generatore in questo modo: for i in common: print(i). I generatori sono iterabili che vengono frequentemente utilizzati al posto di altri iterabili come gli elenchi.
cowlinator
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.