Come posso confrontare due elenchi in Python e restituire corrispondenze


381

Voglio prendere due elenchi e trovare i valori che appaiono in entrambi.

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

returnMatches(a, b)

ritornerebbe [5], per esempio.


4
Le risposte qui sotto mi sembrano tutte sbagliate. Cosa succede se un numero viene ripetuto in entrambi gli elenchi, sicuramente vorresti sapere che (?) (Ad es., Supponiamo che entrambi gli elenchi abbiano '5' due volte) Qualsiasi soluzione che utilizza i set rimuoverà immediatamente tutti gli oggetti ripetuti e perderai quell'informazione.
MH,

Risposte:


487

Non il più efficace, ma di gran lunga il modo più ovvio per farlo è:

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

se l'ordine è significativo puoi farlo con una comprensione dell'elenco come questa:

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

(funziona solo per elenchi di dimensioni uguali, il che significa significato dell'ordine).


15
Una nota di cautela, la comprensione dell'elenco non è necessariamente l'opzione più veloce. Per insiemi più grandi (dove è più probabile che le prestazioni contino) il confronto bit a bit ( &) o set(a).intersection(b)sarà più veloce o più veloce della comprensione dell'elenco.
Joshmaker,

24
Un'altra nota di cautela: la comprensione dell'elenco trova i valori che appaiono in entrambe le posizioni SAME (questo è ciò che SilentGhost intendeva per "ordine è significativo"). Le soluzioni di intersezione impostate troveranno anche corrispondenze in DIVERSE posizioni. Queste sono le risposte a 2 domande abbastanza diverse ... (la domanda dell'op è ambigua su quale si sta ponendo)
drevicko

Come si fa se gli elenchi sono elenchi di elenchi, ovvero a = [[0,0], [1,0]] eb = [[2,3], [0,0]]
Schneems

3
Quale sarebbe la complessità temporale del primo esempio set(a) & set(b)?
AdjunctProfessorFalcon,

Nota, questo non funziona se entrambi i set sono vuoti e ti aspetti che il confronto passi. Quindi cambia in "(imposta (a) e imposta (b)) o (non a e non b)"
Neil McGill

395

Usa set.intersection () , è veloce e leggibile.

>>> set(a).intersection(b)
set([5])

28
Questa risposta ha buone prestazioni algoritmiche, poiché solo una delle liste (più breve dovrebbe essere preferita) viene trasformata in un set per una rapida ricerca e l'altro elenco viene attraversato cercando i suoi elementi nel set.
u0b34a0f6ae,

18
bool(set(a).intersection(b))per TrueoFalse
Akshay,

6
Questa risposta è più flessibile e leggibile, poiché le persone potrebbero aver bisogno differenceo union.
Shihe Zhang,

Che cosa succede se ho oggetti come elementi di elenco e voglio solo corrispondenze parziali, cioè solo alcuni attributi devono corrispondere per essere considerati oggetti corrispondenti?
CGFoX

C'è qualche differenza prestazionale per .intersection()vs &?
Brandonbanks,

106

Un rapido test delle prestazioni che mostra la soluzione di Lutz è il migliore:

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)

Questi sono i risultati sulla mia macchina:

# 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

Ovviamente, qualsiasi test di prestazione artificiale dovrebbe essere eseguito con un granello di sale, ma poiché la set().intersection()risposta è almeno altrettanto veloce delle altre soluzioni e anche la più leggibile, dovrebbe essere la soluzione standard per questo problema comune.


Set in realtà rimuove le ripetizioni, quindi nel mio caso non funzionerà
rgralma il

@rgralma facendo un nuovo setda un esistente listnon rimuoverà nulla dall'originale list. Se vuoi una logica speciale per gestire i duplicati all'interno di un elenco, penso che dovrai porre una nuova domanda perché la risposta dovrà essere specifica per come vuoi che i duplicati vengano gestiti.
Joshmaker,


15

Il modo più semplice per farlo è usare i set :

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

1
La risposta accettata non funziona per gli elenchi che contengono stringhe. Questo lo fa.
Antony,

12

Inoltre puoi provare questo, mantenendo gli elementi comuni in un nuovo elenco.

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

5

Vuoi duplicati? Altrimenti forse dovresti usare i set:


>>> set([1, 2, 3, 4, 5]).intersection(set([9, 8, 7, 6, 5]))
set([5])

Se vuoi davvero elenchi, java2s.com/Code/Python/List/Functiontointersecttwolists.htm >>> intersect ([1, 2, 3, 4, 5], [9, 8, 7, 6, 5]) [5 ]
Timothy Pratley,

Secondo il doc - ... preclude costruzioni soggette a errori come Set ('abc') e 'cbs' a favore del Set più leggibile ('abc'). Intersection ('cbs'). - docs.python.org/library/sets.html
Aaron Newton

5

un altro modo un po 'più funzionale per verificare l'uguaglianza della lista per la lista 1 (lst1) e la lista 2 (lst2) dove gli oggetti hanno profondità uno e che mantiene l'ordine è:

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 

1
Mentre questo codice può rispondere alla domanda, fornire un contesto aggiuntivo riguardo a come e / o perché risolve il problema migliorerebbe il valore a lungo termine della risposta.
Donald Duck,

4

Può usare anche itertools.product.

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

3

Puoi usare

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

3

Puoi usare:

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

Produzione:

set([1, 7, 9])

4
in che modo differisce dalla risposta accettata da 6+ anni fa?
tmdavison,

1
Bene, ho scritto il dettaglio completo con output e buono per il pitone principiante
Adnan Ghaffar

2

Se vuoi un valore 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

La seguente soluzione funziona per qualsiasi ordine di voci di elenco e supporta inoltre entrambe le liste di lunghezza diversa.

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]

1
Numpy ha una funzione specifica per questo:np.intersect1d(list1, list2)
obchardon,

0

L'uso del __and__metodo degli attributi funziona anche.

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

o semplicemente

>>> 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
La domanda era per la lista e nessun set. l'uso &dell'operatore sul set è già una risposta di SilentGhost nella risposta accettata
dWinder

0

Ho appena usato il seguente e ha funzionato per me:

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)

questo stamperebbe quindi 5 nel tuo caso. Probabilmente non è una prestazione grandiosa però.

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.