Eliminar y extraer elementos duplicados de una lista (array) en Python

Negocio

Esta sección describe cómo generar una nueva lista en Python eliminando o extrayendo elementos duplicados de una lista (array).

Aquí se describen los siguientes detalles.

  • Eliminar elementos duplicados y generar nuevos listados
    • No conservar el orden del listado original:set()
    • Conserva el orden del listado original: dict.fromkeys(),sorted()
    • Matriz bidimensional (lista de listas)
  • Extraer los elementos duplicados y generar una nueva lista
    • No conservar el orden del listado original
    • Conserva el orden del listado original
    • Matriz bidimensional (lista de listas)

El mismo concepto puede aplicarse a las tuplas en lugar de a las listas.

Consulte el siguiente artículo para

  • Si quiere determinar si una lista o tupla tiene elementos duplicados
  • Si desea extraer elementos comunes o no comunes entre varios listados en lugar de un solo listado

Tenga en cuenta que las listas pueden almacenar diferentes tipos de datos y son estrictamente diferentes de los arrays. Si quieres manejar arrays en procesos que requieren tamaño de memoria y direcciones de memoria o procesamiento numérico de grandes datos, utiliza array (biblioteca estándar) o NumPy.

Eliminar elementos duplicados y generar nuevos listados

No conservar el orden del listado original: set()

Si no hay necesidad de preservar el orden de la lista original, utilice set(), que genera un conjunto de tipo set.

El tipo set es un tipo de datos que no tiene elementos duplicados. Cuando se pasa una lista u otro tipo de datos a set(), se ignoran los valores duplicados y se devuelve un objeto de tipo set en el que sólo los valores únicos son elementos.

Si quieres que sea una tupla, utiliza tuple().

l = [3, 3, 2, 1, 5, 1, 4, 2, 3]

print(set(l))
# {1, 2, 3, 4, 5}

print(list(set(l)))
# [1, 2, 3, 4, 5]

Por supuesto, también se puede dejar como set. Consulte el siguiente artículo para obtener más información sobre el tipo de conjunto set.

Conserva el orden del listado original: dict.fromkeys(),sorted()

Si desea conservar el orden de la lista original, utilice el método de clase fromkeys() del tipo diccionario o la función incorporada sorted().

dict.fromkeys() crea un nuevo objeto diccionario cuyas claves son listas, tuplas, etc. especificadas en los argumentos. Si se omite el segundo argumento, el valor es None.

Como las claves del diccionario no tienen elementos duplicados, los valores duplicados se ignoran como en set(). Además, se puede pasar un objeto de diccionario como argumento a list() para obtener una lista cuyos elementos son claves de diccionario.

print(dict.fromkeys(l))
# {3: None, 2: None, 1: None, 5: None, 4: None}

print(list(dict.fromkeys(l)))
# [3, 2, 1, 5, 4]

Se ha garantizado desde Python 3.7 (CPython es 3.6) que dict.fromkeys() preserva el orden de la secuencia de argumentos. Las versiones anteriores utilizan la función incorporada sorted() de la siguiente manera.

Especifica el método de tupla de lista index() para el argumento clave de sorted, que devuelve una lista ordenada de elementos.

index() es un método que devuelve el índice del valor (el número del elemento en la lista), que puede especificarse como la clave de sorted() para ordenar la lista basándose en el orden de la lista original. El argumento clave se especifica como un objeto invocable (callable), por lo que no se debe escribir ().

print(sorted(set(l), key=l.index))
# [3, 2, 1, 5, 4]

Matriz bidimensional (lista de listas)

En el caso de las matrices bidimensionales (listas de listas), el método que utiliza set() o dict.fromkeys() produce un TypeError.

l_2d = [[1, 1], [0, 1], [0, 1], [0, 0], [1, 0], [1, 1], [1, 1]]

# l_2d_unique = list(set(l_2d))
# TypeError: unhashable type: 'list'

# l_2d_unique_order = dict.fromkeys(l_2d)
# TypeError: unhashable type: 'list'

Esto se debe a que los objetos no hachables, como las listas, no pueden ser elementos de tipo set ni claves de tipo dict.

Definir las siguientes funciones El orden de la lista original se conserva y funciona para listas y tuplas unidimensionales.

def get_unique_list(seq):
    seen = []
    return [x for x in seq if x not in seen and not seen.append(x)]

print(get_unique_list(l_2d))
# [[1, 1], [0, 1], [0, 0], [1, 0]]

print(get_unique_list(l))
# [3, 2, 1, 5, 4]

Se utiliza la notación de comprensión de listas.

En este caso, utilizamos lo siguiente

  • Si X en «X e Y» es falso en la evaluación de cortocircuito del operador and, entonces Y no se evalúa (no se ejecuta).
  • El método append() devuelve None.

Si los elementos de la lista original seq no existen en la vista, entonces y después se evalúan.
Se ejecuta seen.append(x) y el elemento se añade a seen.
Como el método append() devuelve None y None es False, no visto.append(x) evalúa a True.
La expresión condicional en la notación de comprensión de la lista se convierte en True y se añade como un elemento de la lista final generada.

Si los elementos de la lista original seq están presentes en seen, entonces x no en seen es False, y la expresión condicional para la expresión de comprensión de la lista es False.
Por lo tanto, no se añaden como elementos de la lista final generada.

Otro método es establecer el argumento eje en la función de NumPy np.unique(), aunque el resultado estará ordenado.

Extraer los elementos duplicados y generar una nueva lista

No conservar el orden del listado original

Para extraer sólo los elementos duplicados de la lista original, utilice collections.Counter().
Devuelve un collections.Counter (una subclase de diccionario) con los elementos como claves y el número de elementos como valores.

import collections

l = [3, 3, 2, 1, 5, 1, 4, 2, 3]

print(collections.Counter(l))
# Counter({3: 3, 2: 2, 1: 2, 5: 1, 4: 1})

Al ser una subclase de diccionario, se puede utilizar items() para recuperar claves y valores. Basta con extraer claves cuyo número sea dos o más.

print([k for k, v in collections.Counter(l).items() if v > 1])
# [3, 2, 1]

Conserva el orden del listado original

Como se muestra en el ejemplo anterior, desde Python 3.7, las claves de collections.Counter mantienen el orden de la lista original y así sucesivamente.

En versiones anteriores, la ordenación con sorted() es suficiente, así como la eliminación de elementos duplicados.

print(sorted([k for k, v in collections.Counter(l).items() if v > 1], key=l.index))
# [3, 2, 1]

Si desea extraer los duplicados tal y como están, simplemente deje los elementos de la lista original con un número de dos o más. El orden también se conserva.

cc = collections.Counter(l)
print([x for x in l if cc[x] > 1])
# [3, 3, 2, 1, 1, 2, 3]

Matriz bidimensional (lista de listas)

Para matrices bidimensionales (listas de listas), las siguientes funciones son posibles cuando no se conserva el orden de la lista original y cuando se conserva, respectivamente. También funciona para listas unidimensionales y tuplas.

l_2d = [[1, 1], [0, 1], [0, 1], [0, 0], [1, 0], [1, 1], [1, 1]]
def get_duplicate_list(seq):
    seen = []
    return [x for x in seq if not seen.append(x) and seen.count(x) == 2]

def get_duplicate_list_order(seq):
    seen = []
    return [x for x in seq if seq.count(x) > 1 and not seen.append(x) and seen.count(x) == 1]

print(get_duplicate_list(l_2d))
# [[0, 1], [1, 1]]

print(get_duplicate_list_order(l_2d))
# [[1, 1], [0, 1]]

print(get_duplicate_list(l))
# [3, 1, 2]

print(get_duplicate_list_order(l))
# [3, 2, 1]

Si quiere extraer con duplicados, deje los elementos de la lista original con un recuento de dos o más.

print([x for x in l_2d if l_2d.count(x) > 1])
# [[1, 1], [0, 1], [0, 1], [1, 1], [1, 1]]

Tenga en cuenta que como la complejidad computacional de count() es O(n), la función mostrada anteriormente que ejecuta repetidamente count() es muy ineficiente. Puede haber una forma más inteligente.

Counter es una subclase de dictionary, por lo que si se pasa una lista o tupla cuyos elementos son listas u otros objetos no hachables a collections.Counter(), se producirá un error y no se podrá utilizar.

# print(collections.Counter(l_2d))
# TypeError: unhashable type: 'list'