Duplicaten in lijsten verwijderen

Ik moet een programma schrijven dat controleert of een lijst dubbele items bevat en als dat het geval is verwijdert het deze en geeft een nieuwe lijst terug met de items die niet gedupliceerd/verwijderd zijn. Dit is wat ik heb, maar om eerlijk te zijn weet ik niet wat ik moet doen.

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

De gebruikelijke aanpak om een unieke verzameling van items te krijgen is het gebruik van een set. Sets zijn ongeordende verzamelingen van onderscheidende objecten. Om een set te maken van een iterable, kun je deze doorgeven aan de ingebouwde set() functie. Als je later weer een echte lijst nodig hebt, kun je op dezelfde manier de set doorgeven aan de list() functie.

Het volgende voorbeeld zou alles moeten dekken wat je probeert te doen:

>>> 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]

Zoals je kan zien in het resultaat van het voorbeeld, wordt de originele volgorde niet behouden. Zoals hierboven vermeld, zijn verzamelingen zelf ongeordende verzamelingen, dus de volgorde gaat verloren. Bij het terug converteren van een set naar een lijst, wordt een willekeurige volgorde aangemaakt.

Behoud van volgorde

Als orde belangrijk voor je is, dan zul je een ander mechanisme moeten gebruiken. Een veel gebruikte oplossing hiervoor is om te vertrouwen op OrderedDict om de volgorde van sleutels te behouden tijdens het invoegen:

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

Vanaf Python 3.7, is het ingebouwde woordenboek ook gegarandeerd in staat om de invoegvolgorde te handhaven, dus je kunt dat ook direct gebruiken als je Python 3.7 of later gebruikt (of CPython 3.6):

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

Merk op dat dit de overhead heeft van het eerst maken van een woordenboek, en dan er een lijst van maken. Als je niet echt de volgorde hoeft te bewaren, kun je beter een set gebruiken. Kijk in deze vraag voor meer details en alternatieve manieren om de volgorde te bewaren bij het verwijderen van duplicaten.


Merk tenslotte op dat zowel de set als de OrderedDict/dict oplossingen vereisen dat je items hashable moeten zijn. Dit betekent meestal dat ze onveranderlijk moeten zijn. Als je te maken hebt met items die niet hashable zijn (b.v. lijst objecten), dan zul je een langzame aanpak moeten gebruiken waarbij je in principe elk item moet vergelijken met elk ander item in een geneste lus.

Commentaren (4)

Het is een one-liner: list(set(source_list)) zal de truc doen.

Een set is iets dat onmogelijk duplicaten kan hebben.

Update: een volgorde-onderhoudende aanpak is twee regels:

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

Hier maken we gebruik van het feit dat OrderedDict de invoegvolgorde van sleutels onthoudt, en deze niet wijzigt als een waarde bij een bepaalde sleutel wordt bijgewerkt. We voegen True als waarden in, maar we zouden alles kunnen invoegen, waarden worden gewoon niet gebruikt. (set werkt ook veel als een dict met genegeerde waarden).

Commentaren (3)

Als je niet om de volgorde geeft, doe dan dit:

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

Een set heeft gegarandeerd geen duplicaten.

Commentaren (1)