In dit hoofdstuk bespreken we de class List die in C# reeds voorzien is. Een beschrijving van deze class vind je onder de volgende link.
Een list kan je best vergelijken met een array, maar met veel meer mogelijkheden. Een array van strings zou je zo maken en uitlezen:
// De array names maken.
string[] names = new string[] { "Amrod", "Feanor", "Galadriel", "Legolas"};
// De array names uitlezen.
foreach(var name in names)
{
Console.WriteLine(name);
}
Een List
ziet er net iets anders uit:
// De list names maken.
List<string> names = new List<string> { "Amrod", "Feanor", "Galadriel", "Legolas"};
// De list names uitlezen.
foreach(var name in names)
{
Console.WriteLine(name);
}
Veel verschil lijkt er niet te zijn. Waarom zou je dan een list gebruiken? Een reden is dat je bijvoorbeeld aan een list veel eenvoudiger elementen kan toevoegen en verwijderen, dan aan een array. We gebruiken hiervoor de methods Add
en Remove
die je in de List
class kan terugvinden.
public class ListOfElves
{
private List<string> names = new List<string>(); // empty list
// Een element toevoegen d.m.v. Add(). De waarde die toegevoegd wordt,
// wordt via het argument van de functie meegegeven.
public void AddElf(string name)
{
names.Add(name);
}
// Een element verwijderen d.m.v. Remove(). Het te verwijderen element
// wordt via het argument name meegegeven.
public void RemoveElf(string name)
{
names.Remove(name);
}
public void Print()
{
foreach(var name in names)
{
Console.WriteLine(name);
}
}
}
Het is ook mogelijk om elementen via hun index aan te spreken, of om de index van een element te zoeken. We gebruiken hiervoor de method IndexOf
die je in de List
class kan terugvinden.
Onderstaande functies zouden bijvoorbeeld aan de class ListOfElves toegevoegd kunnen worden:
public class ListOfElves
{
// ... add previous code
// De index van een element zoeken a.h.v. de name van het element.
// De index wordt als een integer als resultaat van de functie gegeven.
// Indien het element met de waarde van name niet gevonden wordt, geeft
// de functie IndexOf() -1 als resultaat.
public int Search(string name)
{
return names.IndexOf(name);
}
// A.h.v. de name nagaan of een element bestaat in de lijst.
// Zoals we hierboven zagen geeft de method IndexOf() -1 als resultaat
// indien er geen element met de opgegeven name in de list aanwezig is.
// IndexOf() wordt in onderstaande functie Exists gebruikt om een boolean te returnen.
// De boolean krijgt de waarde false indien het element niet bestaat, true indien het
// wel in de list zit.
public bool Exists(string name)
{
if(names.IndexOf(name) == -1)
{
return false;
}
return true;
}
// Onderstaande functie haalt het element met een bepaalde index op.
// Er wordt eerst d.m.v. if getest of de opgegeven index geldig is.
// Indien de index geldig is, wordt de waarde van het element als resultaat
// van de functie gegeven.
public string Get(int index)
{
if(index < 0 || index > names.Count - 1) return string.Empty;
return names[index];
}
}
Ook kan je een List
eenvoudig sorteren. We zouden de class hierboven zo kunnen herschrijven dat het sorteren vanzelf gebeurt wanneer je een element toevoegt of verwijdert. We doen dit door de method Sort() toe te voegen aan de functies AddElf() en RemoveElf(). Op die manier wordt de list, telkens er een element toegevoegd of verwijderd wordt, opnieuw gesorteerd. De Sort
functie kan je in de List
class terugvinden.
public class ListOfElves
{
// ...
public void AddElf(string name)
{
names.Add(name);
names.Sort(); // Na het toevoegen van het nieuwe element wordt de list gesorteerd.
}
public void RemoveElf(string name)
{
names.Remove(name);
name.Sort(); // Na het verwijderen van het nieuwe element wordt de list gesorteerd.
}
public void Print()
{
foreach(var name in names)
{
Console.WriteLine(name);
}
}
}
Je kan een List
maken van eender welk type, zoals int
, float
, bool
of double
. Maar ook wanneer je zelf een class ontwerpt, kan je elementen van die class in een list steken.
Hier zie je een voorbeeld van een List<int>
. De List
wordt d.m.v. een for-lus gevuld met de even getallen van 0 tot en met 20.
List<int> evenNumbers = new List<int> {};
for (int i = 0; i <= 20; i+=2)
{
evenNumbers.Add(i);
}
Open het project oefening-list-1 en maak oefeningenreeks 1 en 2
Eigen classes zijn net zo eenvoudig, behalve wanneer je ze wil sorteren. In dat geval moet je twee zaken voorzien:
Sort
via een lambda expressie
. Dat is een nieuw concept waar we nu niet uitgebreid op in gaan, maar het voorbeeld maakt dit duidelijk.Stap 1: De class Elf met daarin functies om Elf-objecten met elkaar te vergelijken. Er is een functie CompareAge() voorzien die Elf-objecten vergelijkt op age. Daarnaast is er een functie CompareName() die Elf-objecten vergelijkt op name.
Van deze class zullen we in stap 2 een List
maken.
public class Elf
{
string Name { private set; get; }
public int Age { private set; get;; }
public Elf(string name, int age)
{
Name = name;
Age = age;
}
// De functie CompareAge vergelijkt de leeftijd van 2 Elf-elementen
// uit de lijst. Als de Elf waarop de functie toegepast wordt jonger is
// dan de Elf die als argument meegegeven wordt, dan geeft de functie -1
// als resultaat, zijn ze even oud dan is het resultaat 0, is de Elf ouder
// dan het argument dan geeft de functie 1 als resultaat.
public int CompareAge(Elf other)
{
if(Age == other.Age)
{
return 0;
}
if(Age < other.Age)
{
return -1;
}
return 1;
}
// De functie CompareName vergelijkt de namen van 2 Elf-elementen
// uit de lijst.
public int CompareName(Elf other)
{
// Omdat name van het type String is, kunnen we de CompareTo() method
// van de String class gebruiken. We moeten deze vergelijking dus niet
// zelf uitwerken zoals bij CompareAge() hierboven. CompareTo zal zelf
// -1, 0 of 1 returnen.
return Name.CompareTo(other.Name);
}
}
Stap 2: De class Elves bevat als property een List
van Elf-elementen. De class Elves bevat eveneens functies die aan de hand van de functies CompareName() en CompareAge() uit de class Elf de List Elves sorteert op respectievelijk Name en Age.
public class Elves
{
List<Elf> list = new List<Elf>();
public void Add(string name, int age)
{
list.Add(new Elf(name, age));
}
// De functie OrderByName() sorteert de lijst alfabetisch op name.
public void OrderByName()
{
list.Sort((a, b) => a.CompareName(b)); // Lambda expressie
//(uitleg: zie onder voorbeeld)
}
// De functie OrderByAge() sorteert de lijst oplopend op Age.
public void OrderByAge()
{
list.Sort((a, b) => a.CompareAge(b)); // Lambda expressie
//(uitleg: zie onder voorbeeld)
}
public void Print()
{
foreach(var elf in list)
{
Console.WriteLine(elf.Name + " is " + elf.Age + " years old.");
}
}
}
Lees de inhoud van Sort
als een soort mini functie, zonder naam. We noemen dit een inline functie. a
en b
zijn de argumenten van de functie. Wat na =>
staat, is wat er gebeurt wanneer de sort functie twee elementen (a en b) wil vergelijken. (Dit werkt dus net zoals de code van een get property) Aangezien de Sort functie in dit geval op een List<Elf>
object toegepast wordt, weten we dat de functie objecten van de class Elf
zal doorgeven als a en b. We voeren dan een functie op object a uit, met object b als argument. Op die manier worden dus respectievelijk de CompareAge() functie en de CompareName() functie van de class Elf
uitgevoerd.
Je zag al dat je met een list ook een gewone foreach kan gebruiken. Maar List
laat je ook toe om dit concept op een andere manier toe te passen. Net zoals Sort
kan je Foreach
ook als functie gebruiken, met daarin een inline functie. Dat kan zo:
List<Account> accounts = new List<Account>();
// (Voeg eerst elementen aan de List toe.)
// Elk element van de List tonen d.m.v. een inline functie.
list.Foreach((account) => { Console.WriteLine(account); });
Het argument tussen de haakjes is dan elke keer een item uit de lijst. De naam mag je zelf kiezen en wordt zo doorgegeven aan de inline functie.
Open het project oefening-list-1 en maak oefeningenreeks 3 en 4