Lijsten sorteren, en de methoden die daarbij horen
Het verschil tussen sorted() en .sort(), de antwoorden die max/min/sum/count/index geven, de regel veranderen met key=, en een lijst omzetten naar leesbare tekst met join().
Hoe wil je leren?
Het probleem dat we oplossen
De cijfers van zeven mensen staan in een lijst. Drie vragen moeten beantwoord worden: wat is het hoogste, wat is het gemiddelde, en wie zijn de top drie?
Met de middelen uit hoofdstuk twaalf kun je de eerste twee klussen met een lus doen — bewerkelijk, maar mogelijk. De derde is anders. "Top drie" betekent dat je ze eerst op volgorde moet zetten, en we hebben nog geen manier om iets te sorteren.
Deze klussen komen zo vaak voor dat Python ze standaard meelevert. Dit hoofdstuk is die lijst met middelen — en één valkuil waar bijna iedereen minstens één keer intrapt: er zijn twee vormen van dezelfde bewerking, één die de lijst verandert en één die een nieuwe teruggeeft, en de verkeerde kiezen geeft helemaal geen fout.
Aan het einde van dit hoofdstuk kun je
- Zeggen wat
sorted()van.sort()onderscheidt, en welke van de twee elke klus nodig heeft - Antwoorden uit een lijst halen met
max,min,sum,countenindex - De regel van een sortering veranderen met
key= - Een lijst omzetten naar leesbare tekst met
join() - Uitleggen waarom het sorteren van een lijst met gemengde types een
TypeErrorgeeft
Voorkennis: Lijsten — veel waarden onder één naam.
sorted() en .sort() — het hart van dit hoofdstuk
Beide sorteren. Het verschil is wat er terugkomt.
marks = [72, 45, 90, 61]
ordered = sorted(marks)
print(ordered)
print(marks)
marks.sort()
print(marks)[45, 61, 72, 90]
[72, 45, 90, 61]
[45, 61, 72, 90]Lees die drie regels output goed door.
sorted(marks) bouwde een nieuwe gesorteerde lijst en gaf die terug. Het originele marks is niet aangeraakt — de tweede regel is het bewijs.
marks.sort() bouwde niets. Het sorteerde de originele lijst, en de oude volgorde is voorgoed weg.
Hier is de regel van hoofdstuk twaalf weer: een methode die de lijst verandert, geeft niets terug.
marks = [72, 45, 90, 61]
marks = marks.sort()
print(marks)NonePrecies zoals append. Met .sort() mag je het resultaat niet bewaren; met sorted() moet je dat juist wel doen, anders is het werk weggegooid.
Welke, wanneer? Als de oorspronkelijke volgorde niet meer nodig is, is .sort() eenvoudiger en goedkoper. Als de originele lijst ergens anders wordt gebruikt, of als je het niet zeker weet, gebruik dan sorted() — dat neemt niets weg van wie dan ook. Bij twijfel: sorted().
Omgekeerde volgorde, en numerieke antwoorden
marks = [72, 45, 90, 61]
print(sorted(marks, reverse=True))
print(max(marks), min(marks), sum(marks))
print(round(sum(marks) / len(marks), 2))[90, 72, 61, 45]
90 45 268
67.0max, min en sum zijn functies en geen methoden, dus het is max(marks) en niet marks.max(). Voor een gemiddelde is er niets speciaals nodig: de som gedeeld door het aantal is het gemiddelde, en round(..., 2) kort het voor de weergave bij.
Merk op dat de optellende lus van hoofdstuk tien in één regel is samengevouwen. Wat je hebt geleerd, is niet verspild — wat sum doet is die lus, en op een dag zul je iets moeten optellen waar Python geen kant-en-klare functie voor heeft.
Tellen en zoeken
marks = [72, 45, 90, 45, 61]
print(marks.count(45))
print(marks.index(45))
print(marks.index(90))2
1
2count(x) zegt hoe vaak x voorkomt. index(x) zegt waar de eerste staat — bij twee 45s meldt hij index 1 en nooit de tweede.
En zoeken naar iets dat er niet is stopt het programma:
marks = [72, 45, 90]
print(marks.index(50))ValueError: 50 is not in listNet als remove. Krijg de gewoonte om eerst te controleren met if 50 in marks:.
Tekst sorteren, en key=
names = ["rafi", "Bilal", "ahmed"]
print(sorted(names))
print(sorted(names, key=str.lower))['Bilal', 'ahmed', 'rafi']
['ahmed', 'Bilal', 'rafi']Mensen zien het eerste resultaat en denken dat Python het fout heeft. Dat heeft het niet — Python sorteert op tekencode, en daar komt elke hoofdletter vóór elke kleine letter. Dus Bilal schoot naar vooraan.
key=str.lower zegt: behandel elke naam bij het sorteren alsof hij kleine letters heeft. De namen zelf veranderen niet — Bilal wordt nog steeds met zijn hoofdletter B afgedrukt — alleen de vergelijking gebruikt de vorm in kleine letters.
key mag elke regel zijn:
words = ["bag", "pen", "notebook", "ink"]
print(sorted(words, key=len))['bag', 'pen', 'ink', 'notebook']Gesorteerd op lengte. Merk op dat bag, pen en ink alle drie tekens lang zijn en in de volgorde waarin ze al stonden bleven staan — Python laat gelijke gevallen met rust. Die eigenschap heet een stabiele sortering, en dankzij hem is sorteren op meerdere criteria mogelijk.
Gemengde types kunnen niet gesorteerd worden
values = [3, "1", 2]
print(sorted(values))TypeError: '<' not supported between instances of 'str' and 'int'Sorteren betekent dingen paar voor paar vergelijken, en hoofdstuk acht liet zien dat een getal en een stuk tekst niet met < vergeleken kunnen worden. De melding is woord voor woord dezelfde. Dit gebeurt standaard bij lijsten die uit een CSV-bestand komen, waar elk getal eigenlijk tekst is.
Van lijst naar tekst — join
Een lijst direct afprinten geeft je haken en aanhalingstekens, en dat is niet om aan iemand te laten zien:
names = ["rafi", "ahmed", "bilal"]
print(", ".join(names))
print(" | ".join(names))rafi, ahmed, bilal
rafi | ahmed | bilalDe regel leest de eerste keer omgekeerd: de verbindende tekst staat eerst, en de lijst gaat tussen de haken. Zo onthoud je het — "verbind deze met dat".
Er is één voorwaarde, en die is streng: elke waarde moet tekst zijn.
marks = [72, 45, 90]
print(", ".join(marks))TypeError: sequence item 0: expected str instance, int foundOm een lijst met getallen te verbinden, maak je van elk eerst tekst:
marks = [72, 45, 90]
print(", ".join(str(m) for m in marks))72, 45, 90Het stuk str(m) for m in marks is nieuw, en een later hoofdstuk behandelt het volledig. Lees het voor nu zo: "voor elke m in marks, maak str(m)." Daarna verbindt join die strings. Het complete voorbeeld hieronder gebruikt dezelfde regel.
Een compleet voorbeeld
report.py:
# A marks report: order them, summarise them, and show the top three
marks = [72, 45, 90, 61, 88, 45, 33]
ordered = sorted(marks, reverse=True)
print("Marks :", marks)
print("Ordered :", ordered)
print("Count :", len(marks))
print("Highest :", max(marks))
print("Lowest :", min(marks))
print("Total :", sum(marks))
print("Average :", round(sum(marks) / len(marks), 2))
print("How many 45s:", marks.count(45))
top_three = ordered[:3]
print("Top three:", top_three)
print("As text :", ", ".join(str(m) for m in top_three))
passed = []
for mark in marks:
if mark >= 40:
passed.append(mark)
print("Passed :", len(passed), "of", len(marks))Marks : [72, 45, 90, 61, 88, 45, 33]
Ordered : [90, 88, 72, 61, 45, 45, 33]
Count : 7
Highest : 90
Lowest : 33
Total : 434
Average : 62.0
How many 45s: 2
Top three: [90, 88, 72]
As text : 90, 88, 72
Passed : 6 of 7Twee ontwerpkeuzes zijn het vermelden waard.
Er is voor sorted() gekozen en niet voor .sort() omdat het originele marks op de eerste regel nog een keer wordt afgedrukt. Met .sort() zouden de regels "Marks" en "Ordered" hetzelfde laten zien en zou niemand er iets van merken. Dat is precies de stille fout waarmee dit hoofdstuk begon.
De top drie kwam uit een slice — ordered[:3]. Er was geen aparte functie voor "top drie" nodig: de eerste drie van een lijst van hoog naar laag zijn de top drie. Als iets eenmaal gesorteerd is, wordt een verrassend aantal vragen één slice.
Wanneer het misgaat
Mijn lijst werd None na het sorteren De regel was marks = marks.sort(). .sort() sorteert de lijst zelf en geeft None terug — schrijf alleen marks.sort(). Voor een nieuwe lijst: ordered = sorted(marks).
Sorteren veranderde ook de originele lijst Je gebruikte .sort(), die ter plekke sorteert. Gebruik sorted() om het origineel met rust te laten.
TypeError: '<' not supported between instances of 'str' and 'int' De lijst mengt getallen en tekst. Draai print(marks) en kijk welke waarden aanhalingstekens eromheen hebben; als het uit een bestand komt, zijn ze waarschijnlijk allemaal tekst en hebben ze int() nodig.
ValueError: 50 is not in list index() of remove() kreeg een waarde die niet in de lijst staat. Controleer eerst met in.
TypeError: sequence item 0: expected str instance, int found join() kreeg een lijst met getallen. Pak elk in met str().
Na het sorteren van namen kwamen alle namen met een hoofdletter eerst Dat is correct gedrag, geen bug. Om te sorteren zoals een mens verwacht: sorted(names, key=str.lower).
Stap 4 van 6 — Voorspellen
Test je begrip
sorted() is gebruikt. Wat drukken de twee regels af?
marks = [72, 45, 90]
ordered = sorted(marks)
print(ordered)
print(marks)- A[45, 72, 90] [72, 45, 90]
- B[45, 72, 90] None
- C[45, 72, 90] [45, 72, 90]
- D[72, 45, 90] [45, 72, 90]
Het resultaat van .sort() wordt teruggeschreven in marks. Wat wordt er afgedrukt?
marks = [72, 45, 90]
marks = marks.sort()
print(marks)- AEen `AttributeError`
- B[72, 45, 90]
- C[45, 72, 90]
- DNone
Er wordt geprobeerd een lijst met getallen door komma's te verbinden. Wat gebeurt er?
marks = [72, 45, 90]
print(", ".join(marks))- AEen `TypeError` — `join` kan alleen tekst verbinden
- B724590
- C72, 45, 90
- D[72, 45, 90]
Voor antwoorden heb je een account nodig
Log in om je antwoorden te controleren
De vragen staan hierboven, en ze in je hoofd uitwerken is waar het om draait. Log in om de antwoorden, de uitleg en de hints in drie niveaus te zien.
Jouw beurt
Schrijf een bestand genaamd inventory.py met een lijst van minstens zeven productnamen en een lijst met hun prijzen.
Print op basis van de prijzen:
- Het hoogste, het laagste, de som en het gemiddelde (op twee decimalen)
- Een nieuwe gesorteerde lijst — en bewijs daarna dat het origineel ongewijzigd is
- De drie duurste, met een slice
Print op basis van de namen:
- Alfabetische volgorde, zonder naar hoofdletters te kijken
- Gesorteerd op de lengte van de naam
- Alle namen op één regel, gescheiden door komma's, met
join
Voer dan één experiment uit: roep .sort() aan op de prijzen en print de regels van deel 1 opnieuw. Welke getallen veranderden en welke niet? Leg jezelf uit waarom de getallen die niet veranderden ook niet konden veranderen — bewaar dat antwoord en de valkuil van dit hoofdstuk zal je nooit te pakken krijgen.
Stap 6 van 6
Uitdaging — de hoofdstukquiz
Tien vragen van makkelijk naar moeilijk. De laatste zijn met opzet lastig.
Log in om de quiz te maken