Comparación de elementos comunes 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)

¡Lo tengo hasta ahora, pero parece que no puedo hacer que funcione!

¿Algunas ideas?


1
Hola, ¿podría agregar algunos detalles sobre cómo planea usar el código? Si esto es para completar una tarea, puede ser mejor elegir una solución que encapsule la forma "Pitónica". Sin embargo, si le preocupa la eficiencia, es poco probable que la forma "pitónica" sea la solución más eficiente. Asesorarnos sobre estos detalles ayudará a las soluciones a resolver su problema.
Matt C

Respuestas:


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

1
1 pero personalmente había frozenset usado ya que es inmutable y así se puede utilizar como clave de diccionario, etc
zebrabox

19
Esto devolverá los elementos / unique / common, pero no los elementos repetidos que puedan existir.
Dologan

@SilentGhost. Cómo obtener el número de elementos coincidentes de dos listas. En este caso es 2.
Poka

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

2
FYI. Esto es definitivamente más rápido que la solución propuesta por Tamás, pero para el caso de uso que estaba viendo cuando terminé en esta página, era importante preservar el orden original de los elementos para los elementos post-filtrados. Este método pierde el orden, mientras que el método de comprensión de la lista conserva el orden. Importante si alguien necesita considerar esto. Gracias.
agftrading

41

También puede usar conjuntos y obtener los puntos en común en una línea: reste el conjunto que contiene las diferencias de uno de los conjuntos.

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

44
Esto convierte A para establecer dos veces, innecesariamente derrochador.
wim

36

Las soluciones propuestas por San Marcos, y SilentGhost generalmente indican cómo se debe hacer de una manera Pythonic, pero pensé que también podría beneficiarse de saber por qué su solución no funciona. El problema es que tan pronto como encuentre el primer elemento común en las dos listas, solo devolverá ese único elemento. Su solución podría solucionarse creando una resultlista y recopilando los elementos comunes en esa lista:

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

Una versión aún más corta que usa comprensiones de listas:

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

Sin embargo, como dije, esta es una forma muy ineficiente de hacer esto: los tipos de conjuntos integrados de Python son mucho más eficientes ya que se implementan en C internamente.


1
Genial para ambas propuestas
dlewin

1
NOTA: Los métodos anteriores solo funcionarán para listas de igual tamaño. Si está trabajando con listas de tamaños desiguales, como yo, entonces deberá evaluar el orden basado en len () antes de llamar a la función: list1 = [2,2,2], list2 [2,3] -> [2,2,2] list1 = [2,3], list2 [2,2,2] -> [2]
redthumb

29

use set intersections, set (list1) y set (list2)

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

Tenga en cuenta que la lista de resultados podría tener un orden diferente con la lista original.


Gracias por la ayuda. Entienda dónde me equivoqué y en qué trabajar la próxima vez. :)
Daniel

55
Gran solución. ¿Hay también una manera de preservar el orden con esto?
tarrasch

14

puedes usar una simple lista de comprensión:

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

9

Establecer es otra forma en que podemos resolver esto

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

9

lista1 = [1,2,3,4,5,6] lista2 = [3,5,7,9]

Sé que 3 formas pueden resolver esto. Por supuesto, podría haber más.

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)

La tercera forma es la más rápida porque los conjuntos se implementan utilizando tablas hash.


8

Las respuestas anteriores funcionan para encontrar los elementos comunes únicos, pero no tendrán en cuenta los elementos repetidos en las listas. Si desea que los elementos comunes aparezcan en el mismo número que los que se encuentran en común en las listas, puede usar la siguiente línea:

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

La or Trueparte solo es necesaria si espera que se evalúe algún elemento False.


Impresionante solución, parece la más completa, aunque un poco escueta
Hendeca

¡Esta debería ser la respuesta que debería haber sido seleccionada! Supongo que también funciona para listas desiguales. Además, la mayoría de las soluciones usan lo setque no es estable (también conocido como el orden se pierde).
Lifebalance

7

Comparé cada uno de los métodos que menciona cada respuesta. En este momento uso Python 3.6.3 para esta implementación. Este es el código que he usado:

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

Si ejecuta este código, puede ver que si usa la lista o el generador (si itera sobre el generador, no solo lo usa. Lo hice cuando forcé al generador a imprimir la longitud), obtendrá casi el mismo rendimiento. Pero si usa set, obtendrá un rendimiento mucho mejor. Además, si utiliza el método de intersección, obtendrá un rendimiento un poco mejor. El resultado de cada método en mi computadora aparece a continuación:

  1. método1: 0.8150673999999999974619413478649221360683441
  2. método2: 0.8329545000000001531148541289439890533685684
  3. Método3: 0.0016547000000000089414697868051007390022277
  4. Método 4: 0.0010262999999999244948867271887138485908508

5

esta es mi propuesta, creo que es más fácil con conjuntos que con un bucle 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 qué no usar list comprehension?

Solución de media línea:

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

0

1) Método1 guardar lista1 es diccionario y luego iterar cada elemento en 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)

Encontrar elementos comunes y diferentes:

2) Método2 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 generador:

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

La ventaja aquí es que esto volverá en tiempo constante (casi instantáneo) incluso cuando se utilicen listas enormes u otros iterables enormes.

Por ejemplo,

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

Todas las demás respuestas aquí llevarán mucho tiempo con estos valores para list1 y list2.

Luego puede iterar la respuesta con

for i in common: print(i)

O conviértalo a una lista con

list(i)

Esto no produce una respuesta. El resultado es un generador en lugar de la lista de elementos comunes.
josiekre

1
Correcto, crea un generador, que es una respuesta. La pregunta era obtener de alguna manera los elementos comunes de las 2 listas, lo que hace este generador. Basta con recorrer el generador de este modo: for i in common: print(i). Los generadores son iterables que se usan con frecuencia en lugar de otros iterables, como las listas.
Cowlinator
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.