Fjernelse af dubletter i lister

Jeg har stort set brug for at skrive et program til at kontrollere, om en liste har nogen dubletter, og hvis den gør det fjerner den dem og returnerer en ny liste med de elementer, der ikke blev dubleret/fjernet. Dette er hvad jeg har, men for at være ærlig ved jeg ikke hvad jeg skal gøre.

def remove_duplicates():
    t = ['a', 'b', 'c', 'd']
    t2 = ['a', 'c', 'd']
    for t in t2:
        t.append(t.remove())
    return t
Løsning

Den almindelige metode til at få en unik samling af elementer er at bruge en [set] (http://docs.python.org/3/library/stdtypes.html#set-types-set-frozenset). Sæt er uordnede samlinger af distinkte objekter. For at oprette et sæt fra en hvilken som helst iterabel, kan du blot sende den til den indbyggede set() funktion. Hvis du senere har brug for en rigtig liste igen, kan du på samme måde sende sættet til funktionen list().

Det følgende eksempel burde dække det, som du forsøger at gøre:

>>> t = [1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> t
[1, 2, 3, 1, 2, 5, 6, 7, 8]
>>> list(set(t))
[1, 2, 3, 5, 6, 7, 8]
>>> s = [1, 2, 3]
>>> list(set(t) - set(s))
[8, 5, 6, 7]

Som du kan se af resultatet i eksemplet, er den oprindelige rækkefølge ikke opretholdt. Som nævnt ovenfor er sæt i sig selv uordnede samlinger, så rækkefølgen går tabt. Når et sæt konverteres tilbage til en liste, oprettes en vilkårlig rækkefølge.

Opretholdelse af rækkefølgen

Hvis orden er vigtig for dig, skal du bruge en anden mekanisme. En meget almindelig løsning til dette er at stole på OrderedDict til at bevare rækkefølgen af nøgler under indsættelse:

>>> from collections import OrderedDict
>>> list(OrderedDict.fromkeys(t))
[1, 2, 3, 5, 6, 7, 8]

Fra og med Python 3.7 er den indbyggede ordbog garanteret til også at opretholde indsættelsesrækkefølgen, så du kan også bruge den direkte, hvis du er på Python 3.7 eller nyere (eller CPython 3.6):

>>> list(dict.fromkeys(t))
[1, 2, 3, 5, 6, 7, 8]

Bemærk at dette har det overhead at oprette en ordbog først, og derefter oprette en liste fra den. Hvis du faktisk ikke har brug for at bevare rækkefølgen, er du bedre tjent med at bruge et sæt. Se dette spørgsmål for flere detaljer og alternative måder at bevare rækkefølgen på, når du fjerner dubletter.


Bemærk endelig, at både set og OrderedDict/dict-løsningerne kræver, at dine elementer er hashable. Dette betyder normalt, at de skal være uforanderlige. Hvis du skal håndtere elementer, der ikke er hashable (f.eks. listeobjekter), skal du bruge en langsom fremgangsmåde, hvor du grundlæggende skal sammenligne hvert element med hvert andet element i en indlejret løkke.

Kommentarer (4)

Det er en enkelt linje: list(set(source_list)) er tilstrækkeligt.

Et set er noget, der umuligt kan have dubletter.

Opdatering: en ordrebevarende fremgangsmåde er to linjer:

from collections import OrderedDict
OrderedDict((x, True) for x in source_list).keys()

Her bruger vi det faktum, at OrderedDict husker nøglernes indsættelsesrækkefølge og ikke ændrer den, når en værdi på en bestemt nøgle opdateres. Vi indsætter True som værdier, men vi kunne indsætte hvad som helst, værdierne bruges bare ikke. (set fungerer også meget som en dict med ignorerede værdier).

Kommentarer (3)

Hvis du er ligeglad med rækkefølgen, kan du bare gøre dette:

def remove_duplicates(l):
    return list(set(l))

Et set har garanteret ingen dubletter.

Kommentarer (1)