Eliminar i extreure elements duplicats d’una llista (matriu) a Python

Negocis

Aquesta secció descriu com generar una llista nova a Python eliminant o extraient elements duplicats d’una llista (matriu).

Els detalls següents es descriuen aquí.

  • Elimina els elements duplicats i genera nous llistats
    • No conserveu l’ordre de la llista original:set()
    • Conserva l’ordre de la llista original:dict.fromkeys(),sorted()
    • Matriu bidimensional (llista de llistes)
  • Extraieu elements duplicats i genereu una llista nova
    • No conserveu l’ordre de la llista original
    • Conserva l’ordre de la llista original
    • Matriu bidimensional (llista de llistes)

El mateix concepte es pot aplicar a tuples en lloc de llistes.

Consulteu l’article següent

  • Si voleu determinar si una llista o tupla té elements duplicats
  • Si voleu extreure elements que són comuns o no comuns entre diversos llistats en lloc d’un sol llistat

Tingueu en compte que les llistes poden emmagatzemar diferents tipus de dades i són estrictament diferents de les matrius. Si voleu gestionar matrius en processos que requereixen mida de memòria i adreces de memòria o processament numèric de dades grans, utilitzeu array (biblioteca estàndard) o NumPy.

Elimina els elements duplicats i genera nous llistats

No conserveu l’ordre de la llista original:set()

Si no cal conservar l’ordre de la llista original, utilitzeu set(), que genera un conjunt de tipus set.

El tipus de conjunt és un tipus de dades que no té elements duplicats. Quan es passa una llista o un altre tipus de dades a set(), els valors duplicats s’ignoren i es retorna un objecte de tipus set en el qual només són elements els valors únics.

Si voleu convertir-lo en una tupla, feu servir 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]

Per descomptat, també es pot deixar configurat. Consulteu l’article següent per obtenir més informació sobre el conjunt de tipus de conjunt.

Conserva l’ordre de la llista original:dict.fromkeys(),sorted()

Si voleu conservar l’ordre de la llista original, utilitzeu el mètode de classe fromkeys() del tipus de diccionari o la funció integrada sortd().

dict.fromkeys() crea un nou objecte de diccionari les claus del qual són llistes, tuples, etc. especificades als arguments. Si s’omet el segon argument, el valor és Cap.

Com que les claus del diccionari no tenen elements duplicats, els valors duplicats s’ignoren com a set(). A més, un objecte de diccionari es pot passar com a argument a list() per obtenir una llista els elements de la qual són claus de diccionari.

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

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

S’ha garantit des de Python 3.7 (CPython és 3.6) que dict.fromkeys() conserva l’ordre de la seqüència d’arguments. Les versions anteriors utilitzen la funció integrada sortd() de la següent manera.

Especifiqueu el mètode de tupla de llista index() per a la clau d’argument de sortd, que retorna una llista ordenada d’elements.

index() és un mètode que retorna l’índex del valor (el número de l’element de la llista), que es pot especificar com a clau de sortd() per ordenar la llista segons l’ordre de la llista original. La clau de l’argument s’especifica com a objecte cridable, per tant, no escriviu ().

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

Matriu bidimensional (llista de llistes)

Per a matrius bidimensionals (llistes de llistes), el mètode que utilitza set() o dict.fromkeys() dóna com a resultat 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'

Això es deu al fet que els objectes no hashable, com ara llistes, no poden ser elements de tipus set o claus de tipus dict.

Definiu les funcions següents L’ordre de la llista original es conserva i funciona per a llistes i tuples unidimensionals.

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]

S’utilitza la notació de comprensió de llista.

Aquí, fem servir el següent

  • Si X a “X i Y” és fals a l’avaluació de curtcircuit de l’operador i, aleshores Y no s’avalua (no s’executa).
  • El mètode append() no retorna Cap.

Si els elements de la llista original seq no existeixen al seen, llavors i després s’avaluen.
seen.append(x) s’executa i l’element s’afegeix a seen.
Com que el mètode append() retorna Cap i Cap és Fals, not seen.append(x) s’avalua com a True.
L’expressió condicional de la notació de comprensió de la llista esdevé True i s’afegeix com a element de la llista generada final.

Si els elements de la llista original seq estan presents a seen, aleshores x not in seen és Fals i l’expressió condicional per a l’expressió de comprensió de la llista és Falsa.
Per tant, no s’afegeixen com a elements de la llista final generada.

Un altre mètode és establir l’eix de l’argument a la funció de NumPy np.unique(), encara que el resultat s’ordenarà.

Extraieu elements duplicats i genereu una llista nova

No conserveu l’ordre de la llista original

Per extreure només elements duplicats de la llista original, utilitzeu collections.Counter().
Retorna un comptador de col·leccions (una subclasse de diccionari) amb els elements com a claus i el nombre d’elements com a valors.

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

Com que és una subclasse de diccionari, items() es pot utilitzar per recuperar claus i valors. N’hi ha prou amb extreure claus el nombre de les quals sigui dos o més.

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

Conserva l’ordre de la llista original

Com es mostra a l’exemple anterior, des de Python 3.7, les claus de les col·leccions.Comptador conserven l’ordre de la llista original i així successivament.

En versions anteriors, l’ordenació amb sorted() és suficient, així com la supressió d’elements duplicats.

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

Si voleu extreure duplicats tal com són, simplement deixeu els elements de la llista original amb un nombre de dos o més. També es conserva l’ordre.

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

Matriu bidimensional (llista de llistes)

Per a matrius bidimensionals (llistes de llistes), les funcions següents són possibles quan no es manté l’ordre de la llista original i quan es manté, respectivament. També funciona per a llistes i tuples unidimensionals.

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 voleu extreure amb duplicats, deixeu els elements de la llista original amb un recompte 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]]

Tingueu en compte que com que la complexitat computacional de count() és O(n), la funció mostrada a dalt que executa repetidament count() és molt ineficient. Pot ser que hi hagi una manera més intel·ligent.

Counter és una subclasse de diccionari, de manera que si passeu una llista o una tupla els elements de la qual són llistes o altres objectes no hashable a col·leccions. Counter(), es produirà un error i no podreu utilitzar-lo.

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