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?

Daniel
fuente
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]
SilentGhost
fuente
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))
BeyondRubicon
fuente
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.

Tamás
fuente
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.


fuente
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]
Mahdi Ghelichi
fuente
9

Establecer es otra forma en que podemos resolver esto

a = [3,2,4]
b = [2,3,5]
set(a)&set(b)
{2, 3}
nEO
fuente
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.

Mahmoud Reda
fuente
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.

Dologan
fuente
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
Saber Solooki
fuente
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))
Elasri
fuente
2

¿Por qué no usar list comprehension?

Solución de media línea:

common_elements = [x for x in list1 if x in list2]
seralouk
fuente
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) 
JS
fuente
-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)
cowlinator
fuente
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