¿Cómo puedo comparar dos listas en python y devolver coincidencias?

381

Quiero tomar dos listas y encontrar los valores que aparecen en ambas.

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

returnMatches(a, b)

volvería [5], por ejemplo.

tehryan
fuente
44
Las respuestas a continuación me parecen incorrectas. Qué sucede si se repite un número en cualquiera de las listas, seguramente querrá saber que (?) (Por ejemplo, digamos que ambas listas tienen '5' dos veces) Cualquier solución que use conjuntos eliminará inmediatamente todos los elementos repetidos y perderá esa información
MH
Posible duplicado de ¿Cómo encontrar la intersección de la lista?
Kushan Gunasekera

Respuestas:

487

No es la más eficiente, pero la forma más obvia de hacerlo es:

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

Si el orden es significativo, puede hacerlo con listas de comprensión como esta:

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

(solo funciona para listas de igual tamaño, lo que implica la importancia del orden).

SilentGhost
fuente
15
Una nota de precaución, la comprensión de la lista no es necesariamente la opción más rápida. Para conjuntos más grandes (donde es más probable que el rendimiento importe), la comparación a nivel de bits ( &) o set(a).intersection(b)será tan rápida o más rápida que la comprensión de la lista.
Joshmaker
24
Otra nota de precaución: la comprensión de la lista encuentra los valores que aparecen en ambas en las MISMAS posiciones (esto es lo que SilentGhost quiso decir con "el orden es significativo"). Las soluciones de intersección establecidas también encontrarán coincidencias en DIFERENTES posiciones. Estas son respuestas a 2 preguntas muy diferentes ... (la pregunta del
operador
¿Cómo se hace esto si sus listas son listas de listas, es decir a = [[0,0], [1,0]] yb = [[2,3], [0,0]]
Schneems
3
¿Cuál sería la complejidad temporal del primer ejemplo set(a) & set(b)?
AdjunctProfessorFalcon
Tenga en cuenta que esto no funciona si ambos conjuntos están vacíos y espera que se pase la comparación. Así que cambie a "(set (a) y set (b)) o (no a and not b)"
Neil McGill
395

Use set.intersection () , es rápido y legible.

>>> set(a).intersection(b)
set([5])
Dennis
fuente
28
Esta respuesta tiene un buen rendimiento algorítmico, ya que solo una de las listas (debe preferirse una más corta) se convierte en un conjunto para una búsqueda rápida, y la otra lista se recorre buscando sus elementos en el conjunto.
u0b34a0f6ae
18
bool(set(a).intersection(b))para TrueoFalse
Akshay
66
Esta respuesta es más flexible y legible, ya que las personas pueden necesitar differenceo union.
Shihe Zhang el
¿Qué sucede si tengo objetos como elementos de lista y solo quiero coincidencias parciales, es decir, solo algunos atributos tienen que coincidir para que se considere un objeto coincidente?
CGFoX
¿Hay alguna diferencia de rendimiento para .intersection()vs &?
brandonbanks
106

Una prueba rápida de rendimiento que muestra la solución de Lutz es la mejor:

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)

Estos son los resultados en mi 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, cualquier prueba de rendimiento artificial debe tomarse con un grano de sal, pero dado que la set().intersection()respuesta es al menos tan rápida como las otras soluciones, y también la más legible, debería ser la solución estándar para este problema común.

Joshmaker
fuente
Set en realidad está eliminando repeticiones, por lo que en mi caso no funcionará
rgralma
@rgralma haciendo un nuevo a setpartir de uno existente listno eliminará nada del original list. Si desea una lógica especial para manejar duplicados dentro de una lista, creo que tendrá que hacer una nueva pregunta porque la respuesta deberá ser específica de cómo desea que se manejen los duplicados.
Joshmaker
67

Prefiero las respuestas basadas en el conjunto, pero aquí hay una que funciona de todos modos

[x for x in a if x in b]
SingleNegationElimination
fuente
15

La forma más fácil de hacerlo es usar conjuntos :

>>> a = [1, 2, 3, 4, 5]
>>> b = [9, 8, 7, 6, 5]
>>> set(a) & set(b)
set([5])
Greg Hewgill
fuente
15

Manera rápida:

list(set(a).intersection(set(b)))
DesplazadoAussie
fuente
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'])**
Setz
fuente
1
La respuesta aceptada no funciona para listas que contienen cadenas. Este sí.
Antony
12

También puede intentar esto manteniendo elementos comunes en una nueva lista.

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

¿Quieres duplicados? Si no, tal vez debería usar conjuntos en su lugar:


>>> set([1, 2, 3, 4, 5]).intersection(set([9, 8, 7, 6, 5]))
set([5])
Timothy Pratley
fuente
Si realmente quiere listas, java2s.com/Code/Python/List/Functiontointersecttwolists.htm >>> intersect ([1, 2, 3, 4, 5], [9, 8, 7, 6, 5]) [5 ]
Timothy Pratley, el
De acuerdo con el documento - ... excluye construcciones propensas a errores como Set ('abc') y 'cbs' a favor de la intersección Set ('abc'). Más legible ('cbs'). - docs.python.org/library/sets.html
Aaron Newton
5

Otra forma un poco más funcional de verificar la igualdad de la lista para la lista 1 (lst1) y la lista 2 (lst2) donde los objetos tienen profundidad uno y que mantiene el orden es:

all(i == j for i, j in zip(lst1, lst2))   
importa
fuente
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 
Harish Verma
fuente
1
Si bien este código puede responder la pregunta, proporcionar un contexto adicional sobre cómo y / o por qué resuelve el problema mejoraría el valor a largo plazo de la respuesta.
Donald Duck
4

Puede usar itertools.product también.

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

Puedes usar

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

Puedes usar:

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

Salida:

set([1, 7, 9])
Adnan Ghaffar
fuente
44
¿En qué se diferencia esto de la respuesta aceptada de hace más de 6 años?
tmdavison el
1
Bueno, escribí el detalle completo con salida y bueno para Python principiante
Adnan Ghaffar
2

Si desea un 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
Matheus Araujo
fuente
1

La siguiente solución funciona para cualquier orden de elementos de la lista y también admite que ambas listas tengan una longitud 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]
Hafizur Rahman
fuente
1
Numpy tiene una función específica para eso:np.intersect1d(list1, list2)
obchardon el
0

Usar el __and__método de atributo también funciona.

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

o simplemente

>>> set([1, 2, 3, 4, 5]).__and__(set([9, 8, 7, 6, 5]))
set([5])
>>>    
SuperNova
fuente
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.
ravi tanwar
fuente
44
La pregunta era para lista y sin conjunto. El uso del &operador en el set ya fue respondido por SilentGhost en la respuesta aceptada
dWinder
0

Solo usé lo siguiente y funcionó para mí:

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)

Esto imprimiría 5 en su caso. Sin embargo, probablemente no sea un gran rendimiento.

LRBrady
fuente