Python: Duplicaten uit een lijst verwijderen (vijf oplossingen)
Als je duplicaten uit een Python-lijst wilt verwijderen en de volgorde wilt behouden, maak een dictionary van de lijst en haal vervolgens de keys op als nieuwe lijst: list(dict.fromkeys(my_list)).
Een Pythonlist is een geordende reeks die dubbele waarden kan bevatten. Sommige Python-toepassingen vereisen een lijst met alleen unieke elementen. Er zijn verschillende technieken om duplicaten uit een lijst in Python te verwijderen.
De juiste oplossing hangt ervan af of de toepassing de volgorde van de items in de lijst moet behouden nadat de duplicaten zijn verwijderd. De oplossingen in deze tutorial verschillen ook in leesbaarheid en complexiteit, en sommige maken gebruik van functies in modules van derden.
Wat is een dubbele waarde?
Het is handig om te verduidelijken wat we bedoelen met dubbele waarden voordat we oplossingen presenteren om ze uit een lijst te verwijderen. Twee objecten worden over het algemeen als duplicaten beschouwd wanneer hun waarden gelijk zijn. In Python geeft de gelijkheidsoperator ==True terug wanneer twee objecten dezelfde waarde hebben. Objecten van verschillende datatypen kunnen gelijk zijn:
De float 10.0 en het geheel getal 10 zijn gelijk, en het geheel getal 1 en de boolean True zijn ook gelijk. In de meeste scenario’s worden deze waarden als duplicaten beschouwd.
Sommige Python-datastructuren dwingen unieke waarden af. Een set is een collectie die alleen unieke elementen bevat:
Deze code maakt drie sets met behulp van de accoladesnotatie {}. Elke set bevat objecten die gelijk zijn aan elkaar. Als gelijke objecten van verschillende datatypen aan een set worden toegevoegd, wordt alleen het eerste object opgenomen.
Python vereist ook dat dictionary-keys uniek zijn:
print({10:"Integer 10",10.0:"Float 10"})print({True:"Boolean True",1:"Integer 1"})Mogelijk gemaakt door
De dictionaries in deze code bevatten gelijke keys. Alleen de eerste key blijft behouden. De bijbehorende waarde wordt echter vervangen door de laatste waarde die aan de dictionary is toegevoegd bij een gelijke key. In het eerste voorbeeld is de overgebleven key dus het geheel getal 10, maar de waarde is de string "Float 10". In het tweede voorbeeld is de key True, die gelijk is aan 1, gekoppeld aan de waarde "Integer 1".
Sets en dictionaries spelen een rol in meerdere oplossingen in deze tutorial vanwege hun vereiste van unieke elementen of keys.
Duplicaten uit een lijst verwijderen met een set
De eenvoudigste techniek om duplicaten uit een lijst te verwijderen, is de lijst casten naar een set en daarna weer naar een lijst. Een set kan alleen unieke waarden bevatten. Duplicaten worden daarom weggegooid wanneer ze aan de set worden toegevoegd:
names =["James","Bob","James","Mark","Kate","Sarah","Kate"]print(list(set(names)))Mogelijk gemaakt door
Laten we de stappen bekijken die nodig zijn om duplicaten met deze techniek te verwijderen:
De lijst wordt gecast naar een set, waardoor alle duplicaten worden verwijderd
De set wordt teruggecast naar een nieuwe lijst, die alleen unieke waarden bevat
James en Kate komen twee keer voor in de oorspronkelijke lijst, maar slechts één keer in de uiteindelijke lijst.
Sets zijn echter ongeordende collecties. De volgorde van items in een set wordt niet behouden. Let op dat de namen in de uiteindelijke lijst niet in dezelfde volgorde staan als in de oorspronkelijke lijst. Dezelfde code kan een andere volgorde opleveren wanneer je die opnieuw uitvoert of wanneer je een andere Python-interpreter gebruikt, omdat er geen garantie is voor de volgorde van elementen in een set.
Deze oplossing is ideaal wanneer het acceptabel is om informatie over de volgorde van de items in de lijst te verliezen. We hebben echter andere oplossingen nodig als de volgorde behouden moet blijven.
Duplicaten uit een lijst verwijderen en volgorde behouden
Dictionary-keys lijken op sets omdat ze uniek moeten zijn. Een dictionary kan dubbele waarden hebben, maar geen dubbele keys.
Vóór Python 3.6 behielden dictionaries de volgorde van hun elementen niet. Als neveneffect van wijzigingen in de implementatie van dictionaries in Python 3.6 behouden dictionaries nu de volgorde waarin items worden toegevoegd. Dit was in Python 3.6 slechts een implementatiedetail, maar werd in Python 3.7 een formeel onderdeel van de taal.
De functie dict.fromkeys() maakt een dictionary van een iterable. De elementen van de iterable worden de keys van de nieuwe dictionary:
names =["James","Bob","James","Mark","Kate","Sarah","Kate"]print(dict.fromkeys(names))Mogelijk gemaakt door
{'James': None, 'Bob': None, 'Mark': None, 'Kate': None, 'Sarah': None}Mogelijk gemaakt door
Omdat de keys in een dictionary uniek zijn, worden de dubbele waarden genegeerd bij het maken van de dictionary. De keys hebben gegarandeerd dezelfde volgorde als de items in de lijst als je Python 3.7 of later gebruikt. Alle keys hebben standaard de waarde None. De waarden zijn echter niet nodig, want deze dictionary kan weer naar een lijst worden gecast:
names =["James","Bob","James","Mark","Kate","Sarah","Kate"]print(list(dict.fromkeys(names)))Mogelijk gemaakt door
Bij het casten van een dictionary naar een lijst worden alleen de keys gebruikt. Deze techniek zet de oorspronkelijke lijst om naar een nieuwe lijst zonder duplicaten en met behoud van de oorspronkelijke volgorde van de items.
Andere opties om duplicaten uit een lijst te verwijderen
De opties in het eerste deel van deze tutorial dekken de twee scenario’s waarin duplicaten uit een lijst moeten worden verwijderd:
Gebruik een set wanneer de volgorde van items niet nodig is.
Gebruik dict.fromkeys() om de volgorde van de items te behouden.
Deze twee opties zijn waarschijnlijk in de meeste situaties de beste oplossingen. Er zijn echter andere technieken om duplicaten uit een lijst te verwijderen.
Een loop gebruiken om een nieuwe lijst te vullen
Een eenvoudige optie is om door de oorspronkelijke lijst te itereren en nieuwe items aan een nieuwe lijst toe te voegen:
names =["James","Bob","James","Mark","Kate","Sarah","Kate"]
unique_names =[]for name in names:if name notin unique_names:
unique_names.append(name)print(unique_names)Mogelijk gemaakt door
De nieuwe lijst unique_names wordt geïnitialiseerd als een lege lijst vóór de for-loop. Een item wordt aan deze nieuwe lijst toegevoegd als het er nog niet in staat. Deze versie behoudt de volgorde van de items in de oorspronkelijke lijst, omdat de for-loop de lijst in volgorde doorloopt.
Deze oplossing kan inefficiënt zijn voor grote lijsten. Neem een langere lijst met willekeurige getallen. We kunnen de prestaties van deze oplossing vergelijken met de versie met dict.fromkeys():
import random
import timeit
data =[random.randint(0,100)for _ inrange(100)]
use_fromkeys ="unique_data = list(dict.fromkeys(data))"
use_for_loop ="""unique_data = []
for item in data:
if item not in unique_data:
unique_data.append(item)"""
from_keys_time = timeit.timeit(use_fromkeys,globals=globals())
for_loop_time = timeit.timeit(use_for_loop,globals=globals())print(f"Time for 'dict.fromkeys()' version: {from_keys_time:0.2f}s")print(f"Time for loop version: {for_loop_time:0.2f}s")Mogelijk gemaakt door
Time for 'dict.fromkeys()' version: 2.26s
Time for loop version: 17.88sMogelijk gemaakt door
De functie timeit() in de module met dezelfde naam meet de uitvoeringstijd van een statement. De statements worden als strings doorgegeven aan timeit.timeit(). De output laat zien dat de for-loopversie aanzienlijk langzamer is dan het gebruik van dict.fromkeys(). De uitvoeringstijden verschillen per computer en setup, maar de optie met dict.fromkeys() zal altijd aanzienlijk sneller zijn.
Een list comprehension met een set gebruiken
De for-loop in de vorige sectie kan niet worden omgezet in een list comprehension, omdat de if-voorwaarde controleert of een item al aan de nieuwe lijst is toegevoegd. Voor een list comprehension is een aparte datastructuur nodig. Een set kan worden gebruikt om bij te houden welke items al aan de lijst zijn toegevoegd:
names =["James","Bob","James","Mark","Kate","Sarah","Kate"]
items =set()
unique_names =[name for name in names ifnot(name in items or items.add(name))]print(unique_names)Mogelijk gemaakt door
Deze tutorial toont deze oplossing voor de volledigheid, maar deze optie is minder leesbaar en biedt geen prestatievoordelen ten opzichte van dict.fromkeys().
Als de naam al in de set items staat, evalueert de expressie tussen haakjes in de list comprehension tot True. De expressie na het sleutelwoord or wordt niet geëvalueerd wanneer de eerste operand True is, omdat or de evaluatie kortsluit. Omdat de expressie tussen haakjes True is, is de if-clausule False en wordt de naam niet toegevoegd aan unique_names.
Als de naam niet in de set items staat, wordt de expressie na het sleutelwoord or geëvalueerd en voegt deze de naam toe aan de set. De methode .add() geeft echter None terug, wat falsy is. De if-clausule is nu True en de naam wordt ook toegevoegd aan de lijst unique_names.
Bibliotheken van derden gebruiken
Een aantal modules van derden heeft tools om duplicaten te verwijderen. Demore_itertools-bibliotheek van derden bevat unique_everseen(), dat eeniterator retourneert die unieke elementen oplevert met behoud van de volgorde.
De bibliotheek more_itertools kan in de terminal worden geïnstalleerd met pip of andere package managers:
We kunnen nu more_itertools.unique_everseen() gebruiken om duplicaten uit een lijst te verwijderen:
import more_itertools
names =["James","Bob","James","Mark","Kate","Sarah","Kate"]
unique_names =list(more_itertools.unique_everseen(names))print(unique_names)Mogelijk gemaakt door
Omdat unique_everseen() een iterator teruggeeft, wordt de output gecast naar een lijst.
Een andere populaire bibliotheek van derden isNumPy, dat ook een oplossing biedt om duplicaten te verwijderen. NumPy kan worden geïnstalleerd met pip of andere package managers:
NumPy’s functie unique() retourneert een NumPy-array met de unieke elementen uit het argument. Deze NumPy-array kan met NumPy’s .tolist() naar een lijst worden omgezet:
import numpy as np
names =["James","Bob","James","Mark","Kate","Sarah","Kate"]
unique_names = np.unique(names).tolist()print(unique_names)Mogelijk gemaakt door
Let er echter op dat NumPy’s unique() de volgorde van de items niet behoudt. In plaats daarvan retourneert het gesorteerde items. Een andere populaire bibliotheek van derden,Pandas, heeft ook een functie unique() die vergelijkbaar werkt maar de volgorde van de items behoudt. De NumPy- en Pandas-oplossingen zijn ideaal wanneer deze bibliotheken al in de codebase worden gebruikt en niet apart hoeven te worden geïnstalleerd en geïmporteerd enkel om duplicaten uit een lijst te verwijderen.
Is dict.fromkeys() beter dan een set gebruiken?
In de meeste gevallen zijn de beste opties de eerste twee die in deze tutorial worden gepresenteerd:
Cast de lijst naar een set en cast de set weer terug naar een lijst.
Maak een dictionary van de lijst met dict.fromkeys() en cast die weer naar een lijst.
Het gebruik van een dictionary behoudt de volgorde van de items. Het gebruik van een set is echter efficiënter en kan prestatiewinst opleveren als de volgorde van de items niet nodig is.
De prestatiewinst kan worden gekwantificeerd met timeit:
import random
import timeit
data =[random.randint(0,100)for _ inrange(100)]
use_fromkeys ="unique_data = list(dict.fromkeys(data))"
use_set ="unique_data = list(set(data))"
from_keys_time = timeit.timeit(use_fromkeys,globals=globals())
set_time = timeit.timeit(use_set,globals=globals())print(f"Time for 'dict.fromkeys()' version: {from_keys_time:0.2f}s")print(f"Time for set version: {set_time:0.2f}s")Mogelijk gemaakt door
Time for 'dict.fromkeys()' version: 2.08s
Time for set version: 1.05sMogelijk gemaakt door
Duplicaten uit een lijst verwijderen met een set is ongeveer twee keer zo snel als met een dictionary.
Conclusie
Python en bibliotheken van derden bieden verschillende opties om duplicaten uit een lijst te verwijderen.
Ik studeerde natuurkunde en wiskunde op bachelorniveau aan de Universiteit van Malta. Daarna verhuisde ik naar Londen en behaalde ik mijn PhD in natuurkunde aan Imperial College. Ik werkte aan nieuwe optische technieken om het menselijk netvlies in beeld te brengen. Nu richt ik me op schrijven over Python, communiceren over Python en lesgeven in Python.
Een Python list is een geordende reeks die dubbele waarden kan bevatten. Sommige Python-toepassingen vereisen een lijst met alleen unieke elementen. Er zijn verschillende technieken om duplicaten uit een lijst in Python te verwijderen.
De juiste oplossing hangt ervan af of de toepassing de volgorde van de items in de lijst moet behouden nadat de duplicaten zijn verwijderd. De oplossingen in deze tutorial verschillen ook in leesbaarheid en complexiteit, en sommige maken gebruik van functies in modules van derden.
Wat is een dubbele waarde?
Het is handig om te verduidelijken wat we bedoelen met dubbele waarden voordat we oplossingen presenteren om ze uit een lijst te verwijderen. Twee objecten worden over het algemeen als duplicaten beschouwd wanneer hun waarden gelijk zijn. In Python geeft de gelijkheidsoperator
==Trueterug wanneer twee objecten dezelfde waarde hebben. Objecten van verschillende datatypen kunnen gelijk zijn:De float
10.0en het geheel getal10zijn gelijk, en het geheel getal1en de booleanTruezijn ook gelijk. In de meeste scenario’s worden deze waarden als duplicaten beschouwd.Sommige Python-datastructuren dwingen unieke waarden af. Een set is een collectie die alleen unieke elementen bevat:
Deze code maakt drie sets met behulp van de accoladesnotatie
{}. Elke set bevat objecten die gelijk zijn aan elkaar. Als gelijke objecten van verschillende datatypen aan een set worden toegevoegd, wordt alleen het eerste object opgenomen.Python vereist ook dat dictionary-keys uniek zijn:
De dictionaries in deze code bevatten gelijke keys. Alleen de eerste key blijft behouden. De bijbehorende waarde wordt echter vervangen door de laatste waarde die aan de dictionary is toegevoegd bij een gelijke key. In het eerste voorbeeld is de overgebleven key dus het geheel getal
10, maar de waarde is de string"Float 10". In het tweede voorbeeld is de keyTrue, die gelijk is aan1, gekoppeld aan de waarde"Integer 1".Sets en dictionaries spelen een rol in meerdere oplossingen in deze tutorial vanwege hun vereiste van unieke elementen of keys.
Duplicaten uit een lijst verwijderen met een set
De eenvoudigste techniek om duplicaten uit een lijst te verwijderen, is de lijst casten naar een set en daarna weer naar een lijst. Een set kan alleen unieke waarden bevatten. Duplicaten worden daarom weggegooid wanneer ze aan de set worden toegevoegd:
Laten we de stappen bekijken die nodig zijn om duplicaten met deze techniek te verwijderen:
James en Kate komen twee keer voor in de oorspronkelijke lijst, maar slechts één keer in de uiteindelijke lijst.
Sets zijn echter ongeordende collecties. De volgorde van items in een set wordt niet behouden. Let op dat de namen in de uiteindelijke lijst niet in dezelfde volgorde staan als in de oorspronkelijke lijst. Dezelfde code kan een andere volgorde opleveren wanneer je die opnieuw uitvoert of wanneer je een andere Python-interpreter gebruikt, omdat er geen garantie is voor de volgorde van elementen in een set.
Deze oplossing is ideaal wanneer het acceptabel is om informatie over de volgorde van de items in de lijst te verliezen. We hebben echter andere oplossingen nodig als de volgorde behouden moet blijven.
Duplicaten uit een lijst verwijderen en volgorde behouden
Dictionary-keys lijken op sets omdat ze uniek moeten zijn. Een dictionary kan dubbele waarden hebben, maar geen dubbele keys.
Vóór Python 3.6 behielden dictionaries de volgorde van hun elementen niet. Als neveneffect van wijzigingen in de implementatie van dictionaries in Python 3.6 behouden dictionaries nu de volgorde waarin items worden toegevoegd. Dit was in Python 3.6 slechts een implementatiedetail, maar werd in Python 3.7 een formeel onderdeel van de taal.
De functie
dict.fromkeys()maakt een dictionary van een iterable. De elementen van de iterable worden de keys van de nieuwe dictionary:Omdat de keys in een dictionary uniek zijn, worden de dubbele waarden genegeerd bij het maken van de dictionary. De keys hebben gegarandeerd dezelfde volgorde als de items in de lijst als je Python 3.7 of later gebruikt. Alle keys hebben standaard de waarde
None. De waarden zijn echter niet nodig, want deze dictionary kan weer naar een lijst worden gecast:Bij het casten van een dictionary naar een lijst worden alleen de keys gebruikt. Deze techniek zet de oorspronkelijke lijst om naar een nieuwe lijst zonder duplicaten en met behoud van de oorspronkelijke volgorde van de items.
Andere opties om duplicaten uit een lijst te verwijderen
De opties in het eerste deel van deze tutorial dekken de twee scenario’s waarin duplicaten uit een lijst moeten worden verwijderd:
dict.fromkeys()om de volgorde van de items te behouden.Deze twee opties zijn waarschijnlijk in de meeste situaties de beste oplossingen. Er zijn echter andere technieken om duplicaten uit een lijst te verwijderen.
Een loop gebruiken om een nieuwe lijst te vullen
Een eenvoudige optie is om door de oorspronkelijke lijst te itereren en nieuwe items aan een nieuwe lijst toe te voegen:
De nieuwe lijst
unique_nameswordt geïnitialiseerd als een lege lijst vóór defor-loop. Een item wordt aan deze nieuwe lijst toegevoegd als het er nog niet in staat. Deze versie behoudt de volgorde van de items in de oorspronkelijke lijst, omdat defor-loop de lijst in volgorde doorloopt.Deze oplossing kan inefficiënt zijn voor grote lijsten. Neem een langere lijst met willekeurige getallen. We kunnen de prestaties van deze oplossing vergelijken met de versie met
dict.fromkeys():De functie
timeit()in de module met dezelfde naam meet de uitvoeringstijd van een statement. De statements worden als strings doorgegeven aantimeit.timeit(). De output laat zien dat defor-loopversie aanzienlijk langzamer is dan het gebruik vandict.fromkeys(). De uitvoeringstijden verschillen per computer en setup, maar de optie metdict.fromkeys()zal altijd aanzienlijk sneller zijn.Een list comprehension met een set gebruiken
De
for-loop in de vorige sectie kan niet worden omgezet in een list comprehension, omdat deif-voorwaarde controleert of een item al aan de nieuwe lijst is toegevoegd. Voor een list comprehension is een aparte datastructuur nodig. Een set kan worden gebruikt om bij te houden welke items al aan de lijst zijn toegevoegd:Deze tutorial toont deze oplossing voor de volledigheid, maar deze optie is minder leesbaar en biedt geen prestatievoordelen ten opzichte van
dict.fromkeys().Als de naam al in de set
itemsstaat, evalueert de expressie tussen haakjes in de list comprehension totTrue. De expressie na het sleutelwoordorwordt niet geëvalueerd wanneer de eerste operandTrueis, omdatorde evaluatie kortsluit. Omdat de expressie tussen haakjesTrueis, is deif-clausuleFalseen wordt de naam niet toegevoegd aanunique_names.Als de naam niet in de set
itemsstaat, wordt de expressie na het sleutelwoordorgeëvalueerd en voegt deze de naam toe aan de set. De methode.add()geeft echterNoneterug, wat falsy is. Deif-clausule is nuTrueen de naam wordt ook toegevoegd aan de lijstunique_names.Bibliotheken van derden gebruiken
Een aantal modules van derden heeft tools om duplicaten te verwijderen. De
more_itertools-bibliotheek van derden bevatunique_everseen(), dat een iterator retourneert die unieke elementen oplevert met behoud van de volgorde.De bibliotheek
more_itertoolskan in de terminal worden geïnstalleerd metpipof andere package managers:We kunnen nu
more_itertools.unique_everseen()gebruiken om duplicaten uit een lijst te verwijderen:Omdat
unique_everseen()een iterator teruggeeft, wordt de output gecast naar een lijst.Een andere populaire bibliotheek van derden is NumPy, dat ook een oplossing biedt om duplicaten te verwijderen. NumPy kan worden geïnstalleerd met
pipof andere package managers:NumPy’s functie
unique()retourneert een NumPy-array met de unieke elementen uit het argument. Deze NumPy-array kan met NumPy’s.tolist()naar een lijst worden omgezet:Let er echter op dat NumPy’s
unique()de volgorde van de items niet behoudt. In plaats daarvan retourneert het gesorteerde items. Een andere populaire bibliotheek van derden, Pandas, heeft ook een functieunique()die vergelijkbaar werkt maar de volgorde van de items behoudt. De NumPy- en Pandas-oplossingen zijn ideaal wanneer deze bibliotheken al in de codebase worden gebruikt en niet apart hoeven te worden geïnstalleerd en geïmporteerd enkel om duplicaten uit een lijst te verwijderen.Is
dict.fromkeys()beter dan een set gebruiken?In de meeste gevallen zijn de beste opties de eerste twee die in deze tutorial worden gepresenteerd:
dict.fromkeys()en cast die weer naar een lijst.Het gebruik van een dictionary behoudt de volgorde van de items. Het gebruik van een set is echter efficiënter en kan prestatiewinst opleveren als de volgorde van de items niet nodig is.
De prestatiewinst kan worden gekwantificeerd met
timeit:Duplicaten uit een lijst verwijderen met een set is ongeveer twee keer zo snel als met een dictionary.
Conclusie
Python en bibliotheken van derden bieden verschillende opties om duplicaten uit een lijst te verwijderen.
Verder leren over Python? Bekijk deze blogposts: