Necesito comparar dos listas para crear una nueva lista de elementos específicos que se encuentran en una lista pero no en la otra. Por ejemplo:
main_list=[]
list_1=["a", "b", "c", "d", "e"]
list_2=["a", "f", "c", "m"]
Quiero recorrer list_1 y agregar a main_list todos los elementos de list_2 que no se encuentran en list_1.
El resultado debería ser:
main_list=["f", "m"]
¿Cómo puedo hacerlo con Python?
list_2
que no aparecen en ninguna partelist_1
o elementoslist_2
que no están presentes en el mismo índicelist_1
?Respuestas:
TL; DR:
SOLUCIÓN (1)
SOLUCIÓN (2) Quiere una lista ordenada
EXPLICACIONES:
(1) Se puede utilizar NumPy de
setdiff1d
(array1
,array2
,assume_unique
=False
).assume_unique
pregunta al usuario si las matrices YA SON ÚNICAS.Si
False
, entonces los elementos únicos se determinan primero.Si
True
, la función asumirá que los elementos ya son únicos Y la función omitirá la determinación de los elementos únicos.Esto produce los valores únicos en
array1
que no están enarray2
.assume_unique
esFalse
por defectoSi le preocupan los elementos únicos (basados en la respuesta de Chinny84 ), simplemente use (where
assume_unique=False
=> el valor predeterminado):(2) Para aquellos que desean ordenar las respuestas, he creado una función personalizada:
Para obtener la respuesta, ejecute:
NOTAS LATERALES:
(a) La solución 2 (función personalizada
setdiff_sorted
) devuelve una lista (en comparación con una matriz en la solución 1).(b) Si no está seguro de si los elementos son únicos, simplemente use la configuración predeterminada de NumPy's
setdiff1d
en las soluciones A y B. ¿Qué puede ser un ejemplo de complicación? Ver nota (c).(c) Las cosas serán diferentes si cualquiera de las dos listas no es única.
Por ejemplo
list_2
no es único:list2 = ["a", "f", "c", "m", "m"]
. Mantenerlist1
como está:list_1 = ["a", "b", "c", "d", "e"]
establecer el valor predeterminado de los
assume_unique
rendimientos["f", "m"]
(en ambas soluciones). SIN EMBARGO, si estableceassume_unique=True
, ambas soluciones dan["f", "m", "m"]
. ¿Por qué? Esto se debe a que el usuario asumió que los elementos son únicos). Por lo tanto, es mejor mantenerassume_unique
a su valor predeterminado. Tenga en cuenta que ambas respuestas están ordenadas.pitónnumpy
fuente
Puedes usar conjuntos:
Salida:
Según el comentario de @JonClements, aquí hay una versión más ordenada:
fuente
unique
elementos, pero ¿qué pasa si tenemos múltiples,m's
por ejemplo, esto no lo recogería?list(set(list_2).difference(list_1))
que evita laset
conversión explícita ...No estoy seguro de por qué las explicaciones anteriores son tan complicadas cuando tiene métodos nativos disponibles:
fuente
Use una lista de comprensión como esta:
Salida:
Editar:
Como se menciona en los comentarios a continuación, con grandes listas, lo anterior no es la solución ideal. Cuando ese es el caso, una mejor opción sería convertir
list_1
a unaset
primera:fuente
list_1
, querrá realizar una conversión previa aset
/frozenset
, por ejemploset_1 = frozenset(list_1)
, luegomain_list = [item for item in list_2 if item not in set_1]
, reduciendo el tiempo de verificación deO(n)
por elemento a (aproximadamente)O(1)
.enumerate()
para eso:[index for (index, item) in enumerate(list_2) if item not in list_1]
Si desea una solución de una línea (ignorando las importaciones) que solo requiere
O(max(n, m))
trabajo para entradas de longitudn
ym
, noO(n * m)
trabajo, puede hacerlo con elitertools
módulo :Esto aprovecha las funciones funcionales que toman una función de devolución de llamada en la construcción, lo que le permite crear la devolución de llamada una vez y reutilizarla para cada elemento sin necesidad de almacenarla en algún lugar (porque la
filterfalse
almacena internamente); las comprensiones de listas y las expresiones generadoras pueden hacer esto, pero es feo. †Eso obtiene los mismos resultados en una sola línea que:
con la velocidad de:
Por supuesto, si las comparaciones están destinadas a ser posicionales, entonces:
debe producir:
(debido a que el valor en
list_2
tiene una coincidencia en el mismo índice enlist_1
), definitivamente debe ir con la respuesta de Patrick , que no implica unalist
s oset
s temporal (incluso siset
s es más o menosO(1)
, tienen un factor "constante" más alto por verificación que las simples verificaciones de igualdad ) e implicaO(min(n, m))
trabajo, menos que cualquier otra respuesta, y si su problema es sensible a la posición, es la única solución correcta cuando los elementos coincidentes aparecen en desplazamientos no coincidentes.†: La forma de hacer lo mismo con una comprensión de la lista como una línea sería abusar del bucle anidado para crear y almacenar valores en el bucle "más externo", por ejemplo:
lo que también proporciona un beneficio de rendimiento menor en Python 3 (porque ahora
set_1
tiene un alcance local en el código de comprensión, en lugar de buscarlo desde el alcance anidado para cada verificación; en Python 2 eso no importa, porque Python 2 no usa cierres para enumere las comprensiones; operan en el mismo ámbito en el que se usan).fuente
salida:
fuente
list_1
es grande ylist_2
no tiene un tamaño trivial, porque implicalen(list_2)
O(n)
escaneos delist_1
, haciéndoloO(n * m)
(dónden
ym
son las longitudes delist_2
ylist_1
respectivamente). Si conviertelist_1
aset
/frozenset
por adelantado, las comprobaciones de contención se pueden realizarO(1)
, haciendo que el trabajo total seaO(n)
de la longitud delist_2
(técnicamenteO(max(n, m))
, ya queO(m)
trabaja para hacer elset
).Yo haría
zip
las listas juntas para compararlas elemento por elemento.fuente
list
s con un solo nuevolist
construido, sin temporarios adicionales , sin costosos controles de contención, etc.Usé dos métodos y encontré un método útil sobre otro. Aquí está mi respuesta:
Mis datos de entrada:
Método 1:
np.setdiff1d
me gusta este enfoque sobre otro porque conserva la posiciónMétodo 2: aunque da la misma respuesta que en el Método 1 pero perturba el orden
Method1
np.setdiff1d
cumple mis requisitos perfectamente. Esta respuesta para información.fuente
Si se debe tener en cuenta el número de ocurrencias, probablemente necesite usar algo como
collections.Counter
:Como se prometió, esto también puede manejar diferentes números de ocurrencias como "diferencia":
fuente
De ser1 elimine los elementos presentes en ser2.
Entrada
ser1 = pd.Series ([1, 2, 3, 4, 5]) ser2 = pd.Series ([4, 5, 6, 7, 8])
Solución
ser1 [~ ser1.isin (ser2)]
fuente