Op Youtube
Deze video maakt deel uit van de IIP playlist van de Youtube channel van Rogier van der Linde.
Let op: deze video's zijn al een paar jaar oud, dus hier en daar kunnen kleine afwijkingen voorkomen met deze cursus, die wel altijd up-to-date is.
Soorten collecties
Een collectie is een verzameling gegevens van hetzelfde type met één naam. Enkele voorbeelden:
- een
stringis een verzamelingchars - een
albumis een verzamelingfoto’s - een
namenlijstis een verzamelingnamen - een
afbeeldingis een verzamelingpixels - de
reeks van Fibonacci(1, 1, 2, 3, 5, 8…) is een verzamelinggetallen - …
Belangrijk: je kan geen verschillende types mixen (bv. getallen en teksten) in één collectie!
Alle klassen (behalve arrays) zitten in de System.Collections.Generic namespace. Om ze te kunnen gebruiken, moet je dus een using toevoegen:
using System;
using System.Collections.Generic;
...
| Klasse | Beschrijving | Te vergelijken met |
|---|---|---|
| Array | vaste lengte; wrapper class rond native C# arrays | vaste stoelen in een wachtzaal |
| List<T> | variabele lengte; toevoegen of verwijderen items kan overal | platenkast |
| Stack<T> | variabele lengte, LIFO (last in, first out): toevoegen en verwijderen aan einde | stapel pannenkoeken |
| Queue<T> | variabele lengte; FIFO (first in, first out): toevoegen aan einde, verwijderen aan begin | wachtrij aan de kassa |
| Dictionary<TKey, Tvalue> | variabele lengte; key-value paren, met unieke keys | lockers met unieke naambordjes |
| HashSet<T> | variabele lengte; lijst unieke waarden | |
| SortedDictionary<TKey, Tvalue> | variabele lengte; als Dictionary, maar dan automatisch gesorteerd op TKey |
In dit hoofdstuk focussen we op arrays en lijsten. Maar je moet de eigenschappen van de andere collecties wel kennen voor de theorie.
Arrays
Arrays maken deel uit van een breder concept, collecties genoemd. .NET biedt verschillende
soorten collecties aan als List, Stack, Queue enz... — zie dit overzicht.
C# als taal kent maar één soort collectie, de array.
Een array is een variabele die verwijst naar een genummerde reeks waarden, startend bij index 0:
Arrays hebben volgende fundamentele eigenschappen:
- het aantal plaatsen is vast
- de plaatsen zijn genummerd vanaf 0
- alle plaatsen hebben hetzelfde type (ofwel
int, ofwelstring, ofwelboolean...) - je kan altijd de waarden instellen of veranderen, de waarden zijn veranderlijk
Zie ook deze vergelijking met lijsten
Declaratie en initialisatie
Voorbeelden:
int[] cijfers = new int[6]; // array van 6 ints
string[] namen = new string[20]; // array van 20 strings
bool[] weekdagenOpen = new bool[7]; // array van 7 bools
Je kunt meteen beginwaarden opgeven tussen accolades, gescheiden met komma's:
int[] getallen = { 5, 8, 3, 12, 7 };
double[] kommagetallen = { 1.5, 10.2, 19.85, 3.1415 };
char[] letters = { 'a', 'b', 'c', 'd' };
string[] fruit = { "appel", "banaan", "citroen" };
Waarden aanpassen
Je kan geen elementen toevoegen of verwijderen in een array; het aantal elementen is vast. Je kan wel de waarde van een element veranderen:
int[] getallen = new int[6]; // array van 6 ints, van 0 tot 5
getallen[0] = -2; // zet getal -2 op eerste plaats
getallen[2] = 7; // zet getal 7 op derde plaats
getallen[4] = 1; // zet getal 1 op vijfde plaats
getallen[5] = 11; // zet getal 11 op zesde (laatste) plaats
string[] namenlijst = new string[5]; // array van 5 strings, van 0 tot 4
namenlijst[0] = "Jef";
namenlijst[1] = "Yasmina";
namenlijst[4] = "Long";
⚠️ type
int heeft standaardwaarde 0
⚠️ type
string heeft standaardwaarde null
Gebruiken
één element opvragen
Je kunt een waarde uitlezen uit een array op basis van de index van dit element (eerste = index 0):
string[] kleuren = { "blauw", "groen", "rood", "geel" };
string eerste = kleuren[0]; // blauw; eerste element heeft index 0
string tweede = kleuren[1]; // groen; tweede element heeft index 1
string laatste = kleuren[kleuren.Length - 1]; // geel; manier om laatste element op te vragen
lengte opvragen
Met de lengte wordt het aantal beschikbare plaatsen bedoeld, niet het aantal plaatsen dat effectief een waarde
gekregen heeft. Gebruik de Length property:
int[] getallen = new int[7]; // array met 7 plaatsen → lengte is 7
getallen[0] = 10;
getallen[2] = 5;
getallen[5] = 7;
int lengte = getallen.Length;
Console.WriteLine($"De lengte van de array is: {lengte}");
De lengte van de array is: 7
inlezen met for-loop
Codevoorbeeld voor het inlezen van een array:
string[] namen = new string[4];
for (int i = 0; i < namen.Length; i++) {
Console.Write($"Geef naam {i + 1} van {namen.Length}: ");
namen[i] = Console.ReadLine();
}
Console.WriteLine("Bedankt!");
Geef naam 1 van 4: Kawtar Geef naam 1 van 4: Arne Geef naam 1 van 4: Dmitri Geef naam 1 van 4: Yolanthe Bedankt!
overlopen met for-loop
Gebruik de for-lus met de Length property als je de index van elk element in de array nodig hebt:
string[] namen = { "Zakaria", "Nelly", "Killian", "Chun" };
for (int i = 0; i < namen.Length; i++)
{
string naam = namen[i]; // element op index i
Console.WriteLine($"{i + 1}. {naam}");
}
1. Zakaria 2. Nelly 3. Killian 4. Chun
overlopen met foreach-loop
Gebruik foreach als je de index van de elementen niet nodig hebt:
int[] numbers = { 2, 5, 9, 3, 4, 6, 7 };
foreach (int num in numbers)
{
Console.WriteLine(num);
}
2 5 9 3 4 6 7
Properties en methodes
De .NET Array class biedt volgende properties en methodes:
| Property | Omschrijving |
|---|---|
Length |
het aantal beschikbare plaatsen in de array |
| Methode | Omschrijving |
|---|---|
Clear() |
reset alle elementen naar de defaultwaarde (0 voor ints, null voor strings enz...) |
Contains() |
controleert of de array een gegeven waarde bevat |
Array.IndexOf() |
zoekt de positie (index) van een gegeven waarde; -1 indien niet gevonden |
Array.Reverse() |
keert de volgorde van de elementen om |
Array.Sort() |
sorteert een gegeven array |
String.Split() |
splitst een string in een array |
String.Join() |
voegt een array samen tot een string |
voorbeeld: nagaan of waarde voorkomt in een array met Contains()
Gebruik Contains() (returnwaarde true of false):
string[] fruit = { "appel", "banaan", "citroen" };
bool gevonden = fruit.Contains("citroen");
if (gevonden)
{
Console.WriteLine("De array bevat het woord \"citroen\"");
}
voorbeeld: positie van een waarde in een array met IndexOf()
Gebruik IndexOf() om de positie te vinden (-1 indien niet gevonden):
string[] fruit = { "appel", "banaan", "citroen" };
int pos = Array.IndexOf(fruit, "citroen");
if (pos > -1)
{
Console.WriteLine($"Het woord \"citroen\" is gevonden op positie {pos}");
}
voorbeeld: array sorteren met Sort()
Gebruik Array.Sort() om een array oplopend te sorteren:
int[] getallen = { 7, 3, 9, 2, 6 };
Array.Sort(getallen); // sorteer getallen van klein naar groot
foreach (int getal in getallen)
{
Console.WriteLine(getal);
}
2 3 6 7 9
Gebruik in combinatie met Array.Reverse() om een array aflopend te sorteren:
int[] getallen = { 7, 3, 9, 2, 6 };
Array.Sort(getallen); // sorteer getallen van klein naar groot
Array.Reverse(getallen); // keer volgorde om
foreach (int getal in getallen)
{
Console.WriteLine(getal);
}
9 7 6 3 2
Samenvoegen en splitsen
De .NET String class biedt volgende methodes:
| Methode | Omschrijving |
|---|---|
split() |
splitst een string in een array |
join() |
voegt een array samen tot een string |
voorbeeld: array samenvoegen tot een string met string.Join()
Gebruik string.Join():
int[] getallen = { 5, 7, 12, 8, 3 }; // → int[] array
string samengevoegd = string.Join(", ", getallen); // "5, 7, 12, 8, 3" → één string
Console.WriteLine(samengevoegd);
5, 7, 12, 8, 3
voorbeeld: string rond spaties splitsen naar een array met Split()
string zin = "dit is een zin met meerdere woorden";
string[] woorden = zin.Split(' '); // verdeel zin in woorden
foreach (string woord in woorden)
{
Console.WriteLine(woord);
}
dit is een zin met meerdere woorden
voorbeeld: string rond karakters splitsen naar een array met Split()
Je kan als parameter van Split() een array van karakters opgeven waarrond gesplitst moet worden:
string txt = "0477/234.56.78"; // → één string
string[] parts2 = txt.Split(new char[] { '/', '.' }); // { "0477", "234", "56", "78" } → string[] array
LINQ extensie methodes
.NET LINQ biedt ook een hoop extensie methodes die je kan gebruiken,
zie 02. NET classes - LINQ extensie methodes voor collecties
Lijsten
Een lijst is een collectie van elementen van één bepaald type (string, int, double, ...). Het verschil met een gewone array is dat het aantal elementen onbepaald is.
Declaratie en initialisatie
Algemene syntax:
List<type> naamLijst = new List<type>(); // type is het type van de elementen in de collectie (int, double, string, ...)
Je mag het ook inkorten tot:
List<type> naamLijst = new(); // korte notatie
Code voorbeelden:
List<int> getallen = new(); // een lijst van int's
List<bool> myList = new(); // een lijst van bool's
List<string> namen = new(); // een lijst van string's
Je kan meteen een aantal beginwaarden meegeven:
List<int> getallen = new() { 5, 12, 7, 9, 3 }; // de lijst getallen bevat 5 elementen: 5, 12, 7, 9 en 3
Waarden aanpassen
Elementen wijzigen doe je net zoals bij arrays eenvoudig met een toewijzing (=). Code voorbeeld:
List<int> getallen = new() { 4, 8, 3 }; // lijst is 4, 8, 3
getallen[1] = 5; // tweede element wijzigen naar 5, lijst is nu: 4, 5, 3
Elementen toevoegen of verwijderen
Gebruik hiervoor de methodes Add(), Remove(), RemoveAt() of Clear().
Voorbeeld voor toevoegen:
List<string> fruit = new(); // declaratie (nieuwe lijst van string's)
fruit.Add("appel"); // lijst bevat 1 element
fruit.Add("banaan"); // lijst bevat 2 elementen
fruit.Add("citroen"); // lijst bevat 3 elementen
Voorbeeld voor verwijderen (enkel de eerst gevonden waarde zal verwijderd worden):
List<int> getallen = new() {2, 5, 7, 5 }; // inhoud van de lijst: 2, 5, 7, 5
getallen.Remove(5); // verwijder element met waarde 5 (enkel eerste); inhoud van de lijst: 2, 7, 5
Je kan een element ook verwijderen op basis van de index met RemoveAt():
List<int> getallen = new() {2, 5, 7, 5 }; // inhoud van de lijst: 2, 5, 7, 5
getallen.RemoveAt(2); // verwijder het derde element; de lijst is nu 2, 5, 5
Met de methode Clear(), kan je alle elementen uit de lijst verwijderen:
List<int> getallen = new() { 2, 5, 7, 5 }; // inhoud van de lijst: 2, 5, 7, 5
getallen.Clear(); // de lijst is nu leeg
Gebruiken
één element opvragen
Je kunt een element uit een lijst opvragen op basis van de index van het element, startend vanaf 0. Code voorbeeld:
List<string> kleuren = new() { "rood", "groen", "blauw" };
string eerste = kleuren[0]; // eerste element heeft index 0
Console.WriteLine($"Het eerste element is: {eerste}");
Console.WriteLine($"Het tweede element is: {kleuren[1]}");
string laatste = kleuren[kleuren.Count - 1]; // manier om laatste element op te vragen
Console.WriteLine($"Het laatste element is: {laatste}");
Het eerste element is: rood Het tweede element is: groen Het laatste element is: blauw
aantal elementen opvragen
Met de property Count kan je het aantal elementen dat op dat moment in de List zit opvragen:
List<int> getallen = new() { 2, 5, 8 };
Console.WriteLine(getallen.Count); // Count property
3
⚠️ voor arrays gebruik je Length, bij lijsten gebruik je Count
inlezen met do-while
Codevoorbeeld voor het inlezen van een lijst:
List<string> namen = new();
string nieuweNaam;
do
{
Console.Write($"Geef de volgende naam (laat leeg om te stoppen): ");
nieuweNaam = Console.ReadLine();
if (!string.IsNullOrWhiteSpace(nieuweNaam)) namen.Add(nieuweNaam);
}
while (!string.IsNullOrWhiteSpace(nieuweNaam));
Console.WriteLine("Bedankt!");
Geef de volgende naam (laat leeg om te stoppen): Kawtar Geef de volgende naam (laat leeg om te stoppen): Arne Geef de volgende naam (laat leeg om te stoppen): Dmitri Geef de volgende naam (laat leeg om te stoppen): Bedankt!
overlopen met for-loop
Indien je de index (positie) van het element in de lijst nodig hebt.
List<string> namen = new() { "Zakaria", "Nelly", "Killian", "Chun" };
for (int i = 0; i < namen.Count; i++)
{
string naam = namen[i];
Console.WriteLine($"{i + 1}. {naam}");
}
1. Zakaria 2. Nelly 3. Killian 4. Chun
overlopen met foreach-loop
Indien je de index (positie) van het element niet nodig hebt kan je foreach gebruiken:
List<string> namen = new() { "Zakaria", "Nelly", "Killian", "Chun" };
foreach (string naam in namen)
{
Console.WriteLine(naam);
}
Zakaria Nelly Killian Chun
Properties en methodes
Een List class biedt volgende properties en methodes:
| Property | Omschrijving |
|---|---|
Count |
het huidig aantal elementen in de lijst |
| Methode | Omschrijving |
|---|---|
Add() |
voeg een waarde toe aan het einde |
Contains() |
controleert of de lijst een gegeven waarde bevat |
IndexOf() |
zoekt de positie (index) van een gegeven waarde; -1 indien niet gevonden |
Insert() |
voeg een waarde in op een gegeven positie |
Remove() |
verwijder een element |
Reverse() |
keert de volgorde van de elementen om |
Sort() |
sorteert een gegeven array |
voorbeeld: nagaan of element voorkomt in lijst met Contains()
Met de methode Contains() kan je nagaan of een element voorkomt in een lijst. De methode stuurt true terug indien de meegegeven waarde zich in de lijst bevindt:
List<string> fruit = new() { "appel", "banaan", "citroen" };
bool gevonden = fruit.Contains("citroen"); // ga na of het woord "citroen" in de lijst voorkomt
if (gevonden)
{
Console.WriteLine("Het element komt wel in de lijst voor");
}
else
{
Console.WriteLine("Het element komt niet in de lijst voor.");
}
Het element komt in de lijst voor
voorbeeld: lijst sorteren met Sort()
De methode Sort() sorteert de elementen in een lijst in oplopende volgorde (van klein naar groot, of voor tekst alfabetische van 'a' tot 'z'):
List<int> getallen = new() { 7, 3, 9, 5 };
getallen.Sort(); // sorteer de elementen in de lijst (volgorde van elementen in lijst zélf verandert!)
foreach (int getal in getallen)
{
Console.WriteLine(getal);
}
3 5 7 9
Samenvoegen en splitsen
elementen in een lijst samenvoegen tot één string met string.Join()
Gebruik string.Join() om elementen van een list samen te voegen tot één string. Het eerste argument is de "lijm" tussen elementen:
List<int> getallen = new() { 7, 3, 9, 5 };
Console.WriteLine(string.Join(" - ", getallen));
7 - 3 - 9 - 5
Voorbeelden voor andere collecties
Stack<T>
Een Stack<T> is als een List<T> maar dan zonder methodes Add() of Remove(), en in plaats daarvan Push() (plaats element op de stapel) en Pop() (pak een element van de stapel):
Stack<int> stack = new Stack<int>(new int[] { 4, 8, 11 });
int val1 = stack.Pop(); // 11
int val2 = stack.Pop(); // 8
stack.Push(23);
int val3 = stack.Pop(); // 23
int val4 = stack.Pop(); // 4
int val5 = stack.Pop(); // FOUT! stack is leeg
Queue<T>
Een Queue<T> is als een List<T> maar dan zonder methodes Add() of Remove(), en in plaats daarvan Enqueue() (plaats element achteraan de wachtrij) en Dequeue() (pak een element vooraan de wachtrij):
Queue<int> queue = new Queue<int>(new int[] { 4, 8, 11 });
int val1 = queue.Dequeue(); // 4
int val2 = queue.Dequeue(); // 8
queue.Enqueue(23);
int val3 = queue.Dequeue(); // 11
int val4 = queue.Dequeue(); // 23
int val5 = queue.Dequeue(); // FOUT! queue is leeg
Dictionary<TKey,Tvalue>
De Dictionary wordt gebruikt voor key-value paren, waarbij de keys uniek moeten zijn. De methodes en properties lijken sterk op List<T>. Voorbeeldfragment met typische methodes en properties:
Dictionary<string, int> dict1 = new Dictionary<string, int> { { "aap", 6 }, { "noot", 3 }, { "mies", -7 } };
dict1["tuin"] = 11; // voeg een nieuw key-value paar toe
dict1.Remove("mies"); // verwijder een key-value paar
dict1["noot"] = 4; // verander de waarde van ene key-value paar
Console.WriteLine($"Dictionary 1 bevat key \"noot\": {(dict1.Keys.Contains("noot") ? "ja" : "nee")}"); // controleer of key bestaat
Console.WriteLine($"Dictionary 1 bevat waarde 3: {(dict1.Values.Contains(3) ? "ja" : "nee")}"); // controleer of value bestaat
foreach (KeyValuePair<string, int> item in dict1)
{
Console.WriteLine($"Key: {item.Key}, Value: {item.Value}");
}
Dictionary 1 bevat key "noot": ja Dictionary 1 bevat waarde 3: nee Key: aap, Value: 6 Key: noot, Value: 4 Key: tuin, Value: 11
HashSet<T>
Een HashSet<T> is hetzelfde als een List<T>, behalve dat de lijst uniek gehouden wordt:
HashSet<string> set = new HashSet<string>(new string[] { "banaan", "appel" });
set.Add("banaan");
set.Add("citroen");
set.Add("banaan");
set.Add("banaan");
set.Add("appel");
set.Add("appel");
set.Add("peer");
Console.WriteLine(string.Join(", ", set));
banaan, appel, citroen, peer
Lijst en array vergeleken
Er zijn nogal wat syntactische verschillen. Een overzichtstabel:
| Array | List | |
|---|---|---|
| lengte | vast | flexibel |
| declaratie | int[] cijfers = new int[3]; |
List<int> cijfers = new(); |
| initialisatie | int[] cijfers = { 4, 1, 11 }; |
List<int> cijfers = new() { 4, 1, 11 }; |
| elementen toevoegen/verwijderen | niet mogelijk | Add(), Remove(), RemoveAt(), Clear() |
| elementen lezen/schrijven | cijfers[i] |
cijfers[i] |
| aantal elementen | cijfers.Length |
cijfers.Count |
| sorteren | Array.Sort(cijfers) |
cijfers.Sort() |
| bevat waarde | cijfers.Contains(4) |
cijfers.Contains(4) |
| string splitten naar... | string txt = "aap noot mies";string[] woorden = txt.Split(' '); |
string txt = "aap noot mies";string[] woorden = txt.Split(' ').ToList(); |
| samenvoegen | string.Join(", ", cijfers) |
string.Join(", ", cijfers) |
Vergelijkend voorbeeld met een aantal typische methodes:
string tekst = "aap noot mies";
string[] woorden = tekst.Split(' ');
Console.WriteLine($"deze tekst bevat {woorden.Length} woorden");
if (woorden.Contains("aap")) Console.WriteLine("de woorden bevatten \"aap\"");
Array.Sort(woorden);
Console.WriteLine($"de woorden, alfabetisch: {string.Join(" - ", woorden)}");
deze tekst bevat 3 woorden de woorden bevatten "aap" de woorden, alfabetisch: aap - mies - noot
List<int> cijfers = new();
cijfers.Add(7);
cijfers.Add(1);
cijfers.Add(-3);
Console.WriteLine($"deze lijst bevat {cijfers.Count} getallen");
if (cijfers.Contains(1)) Console.WriteLine("de lijst bevat de waarde 1");
cijfers.Sort();
Console.WriteLine($"cijfers (van laag naar hoog): {string.Join(", ", cijfers)}");
deze lijst bevat 3 getallen de lijst bevat de waarde 1 cijfers (van laag naar hoog): -3, 1, 7
Lijsten zijn zeker makkelijker in gebruik en flexibeler dan arrays. Arrays nemen dan weer een vaste geheugenruimte in, terwijl voor lijsten bij elke toevoeging nieuw geheugen moet gezocht worden, waardoor ze een stuk trager zijn. Dus:
- gaat het om een vast aantal elementen? → gebruik een array
- gaat het om heel veel elementen? → gebruik een array
- is performantie belangrijk? → gebruik een array
- in alle andere gevallen → gebruik een lijst
LINQ extensie methodes
Linq biedt een aantal extensie methodes met de lambda expressie syntax voor collecties. Een greep uit het aanbod:
| Methode | Omschrijving | Returntype |
|---|---|---|
All() |
controleer of alle items aan een voorwaarde voldoen | bool |
Any() |
controleer of minstens één item aan een voorwaarde voldoet | bool |
Average() |
bepaal het gemiddelde van de items | double |
Count() |
tel het aantal items | int |
Distinct() |
verwijder alle dubbels | IEnumerable |
First() |
geef het eerste item; fout indien niet gevonden | object |
FirstOrDefault() |
geef het eerste item; standaardwaarde (null/0/...) indien niet gevonden |
object |
Last() |
geef het laatste item; fout indien niet gevonden | object |
LastOrDefault() |
geef het laatste item; standaardwaarde (null/0/...) indien niet gevonden |
object |
OrderBy() |
sorteer items op basis van een item waarde | IEnumerable |
Select() |
selecteer van elk item een waarde | IEnumerable |
Sum() |
bepaal de som van de items | int/double |
Take() |
neem de eerste n items | IEnumerable |
Where() |
filter items op basis van een voorwaarde | IEnumerable |
Voorbeelden met arrays:
string[] fruits = { "apple", "pear", "grape", "banana", "banana", "jackfruit", "banana" };
string[] fruitsLength5 = fruits.Where(f => f.Length == 5).ToArray(); // { "apple", "grape" }
int[] fruitLengths = fruits.Select(f => f.Length).ToArray(); // { 5, 4, 5, 6, 9 }
bool containsBanana = fruits.Any(f => f == "banana"); // true
int numBananas = fruits.Count(f => f == "banana"); // 3
string firstLength7 = fruits.FirstOrDefault(f => f.Length == 7); // null
string[] fruitsUnique = fruits.Distinct().ToArray(); // { "apple", "pear", "grape", "banana", "jackfruit" }
string[] fruitsFirst3 = fruits.Take(3).ToArray(); // { "apple", "pear", "grape" }
string[] fruitsByLength = fruits.Distinct().OrderBy(f => f.Length).ToArray(); // { "pear", "apple", "grape", "banana", "jackfruit" }
int[] numbers = { 3, 8, 1, 5, 10 };
double avg = numbers.Average(); // 5.4
int sum = numbers.Sum(); // 27
int lowest = numbers.Min() // 1
int first = numbers.First() // 3
int last = numbers.Last() // 10
- dit werkt even goed met
List<>; gebruik dan waar nodigToList()in plaats vanToArray()om eenIEnumerableom te zetten