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


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

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


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

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.


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


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


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

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

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

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

3

Puedes usar

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

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

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

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]

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

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.

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.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.