Skip to content

Rimuovere/estrarre elementi duplicati da un elenco in Python

Python

Questo articolo descrive come generare un nuovo elenco in Python rimuovendo ed estraendo elementi duplicati da un elenco. Si noti che la rimozione di elementi duplicati equivale a estrarre solo elementi univoci.

  • Rimuovere gli elementi duplicati (Estrai elementi univoci) da un elenco
    • Non mantenere l’ordine dell’elenco originale:set()
    • Mantieni l’ordine dell’elenco originale:dict.fromkeys(), sorted()
    • Per un elenco bidimensionale (elenco di elenchi)
  • Estrai elementi duplicati da un elenco
    • Non mantenere l’ordine dell’elenco originale
    • Mantieni l’ordine dell’elenco originale
    • Per un elenco bidimensionale (elenco di elenchi)

La stessa idea può essere applicata alle tuple invece che alle liste.

Vedere l’articolo seguente per verificare se gli elenchi o le tuple hanno elementi duplicati.

Non mantenere l’ordine dell’elenco originale:set()

Usa set() se non è necessario mantenere l’ordine dell’elenco originale.

Passando un elenco a set(), aggiunge set, che ignora i valori duplicati e conserva solo i valori univoci come elementi.

set può essere riconvertito in una lista o in una tupla con list() o 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]

Ovviamente puoi usare set così com’è. Vedere il seguente articolo per ulteriori informazioni sul set.

Mantieni l’ordine dell’elenco originale:dict.fromkeys(), sorted()

Se vuoi mantenere l’ordine dell’elenco originale, usa dict.fromkeys() o sorted().

dict.fromkeys() crea un nuovo dizionario con chiavi da iterable. Se il secondo argomento viene omesso, il valore è Nessuno.

Poiché una chiave del dizionario non può avere elementi duplicati, i valori duplicati vengono ignorati come set(). Il passaggio di un dizionario a list() contiene un elenco con le chiavi del dizionario come elementi.

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

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

Da Python 3.7 (3.6 per CPython), dict.fromkey() garantisce che l’ordine della sequenza sia preservato. Nelle versioni precedenti, utilizzare la funzione incorporata sorted() come segue.

index() è un metodo che originale richiede l’indice del valore e, specificandolo nella chiave di sorted(), può essere ordinato in base all’ordine dell’elenco.

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

Per un elenco bidimensionale (elenco di elenchi)

Per un elenco bidimensionale (elenco di elenchi), set() o dict.fromkey() genera 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'

Questo perché gli oggetti non hashable come gli elenchi non possono essere impostati come elementi di tipo o chiavi di tipo dict.

Definire la seguente funzione. L’ordine dell’elenco originale viene mantenuto e funziona per elenchi e tuple unidimensionali.

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]

Viene utilizzata la comprensione dell’elenco.

Non mantenere l’ordine dell’elenco originale

Se vuoi estrarre solo elementi duplicati dall’elenco originale, usa collections.Counter() che contiene collections.Counter (sottoclasse del dizionario) la cui chiave è un elemento e il cui valore è il suo conteggio.

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

Perché è una sottoclasse di un dizionario, puoi recuperare chiavi e valori con items(). È possibile estrarre chiavi con più di due conteggi in base alla comprensione dell’elenco.

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

Mantieni l’ordine dell’elenco originale

Come nell’esempio sopra, da Python 3.7, la chiave di collections.Counter conserva l’ordine dell’elenco originale.

Nelle versioni precedenti, puoi ordinare per sorted() come nell’esempio per rimuovere gli elementi duplicati.

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

Se vuoi estrarre in uno stato duplicato, lascia semplicemente due o più elementi di conteggio dall’elenco originale. Anche l’ordine è conservato.

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

Per un elenco bidimensionale (elenco di elenchi)

Per un elenco bidimensionale (elenco di elenchi):

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]
print([x for x in l_2d if l_2d.count(x) > 1])
# [[1, 1], [0, 1], [0, 1], [1, 1], [1, 1]]

Nota che count() richiede O(n), quindi la funzione che esegue count() mostrata sopra è molto inefficiente. Potrebbe esserci modi più intelligenti ed efficienti.

Poiché collections.Counter è una sottoclasse del dizionario, viene generato un errore se si passa un elenco o una tupla i cui elementi non sono utilizzabili come hash, ad esempio un elenco, a collections.Counter().

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