TOC

This article has been localized into Dutch by the community.

Verzamelingen:

Lijsten

C# heeft een arsenaal aan klassen die kunnen werken met lijsten. Ze implementeren de IList interface. De meeste gebruikte lijst is de generische lijst, deze wordt vaak aangeduid met List<T>. De T slaat op het type objecten die opgeslagen worden in de lijst. Dit heeft ook het voordeel dat de compiler zal controleren of je objecten van het correcte type toevoegt aan de lijst. Met andere woorden, List<T> is type-safe.

List lijkt veel op de ArrayList klasse, die heel vaak gebruikt werd voor C# generische lijsten ondersteunde. Je zal dan ook zien dat List veel zaken kan die die Array ook kan (deze implementeert de IList interface ook). In veel gevallen is het makkelijker en simpeler om met List te werken. Zo hoef je bijvoorbeeld geen List maken met een specifieke grootte, je kan de List gewoon aanmaken en .NET zal deze automatisch groter maken naarmate je er items aan toevoegt.

Zoals vermeld slaat de T op het type van de objecten die je in de lijst wil opslaan. In ons eerste voorbeeld toon ik hoe je een lijst maakt die strings moet bevatten:

List<string> listOfStrings = new List<string>();

Hiermee maak je een lege lijst aan, maar er achteraf dingen aan toevoegen is zeer makkelijk met de Add methode:

listOfStrings.Add("a string");

Als je echter dingen probeert toe te voegen die geen string zijn zal je onmiddelijk een melding krijgen van de compiler:

listOfStrings.Add(2);
Error   CS1503  Argument 1: cannot convert from 'int' to 'string'

Een lijst initialiseren met items

In bovenstaand voorbeeld hebben we eerste een lijst gemaakt en er daarna items aan toegevoegd. C# laat ons echter ook toe om een lijst aan te maken en er items aan te toe te voegen in een keer. Hiervoor gebruiken we een techniek die initialisatie van verzamelingen (collection initializers) genoemd wordt. Laat ons even kijken:

List<string> listOfNames = new List<string>()
{
    "John Doe",
    "Jane Doe",
    "Joe Doe"
};

De syntax is zeer simpel, voor de gebruikelijke puntkomma (die we gebruiken om iets af te sluiten) hebben we een set krulhaakjes {} waartussen we een lijst kunnen ingeven om onze List op te vullen. Aangezien dit een lijst is met strings, moet de items die we ingeven ook strings zijn. Dit werkt ook perfect voor lijsten waarin andere types moeten opgeslagen worden, zelfs als we onze eigen klassen gebruiken.

Werken met de items

Er zijn verschillende manieren om te werken met de items uit een generische lijst, om je enkele mogelijkheden te tonen heb ik een groter voorbeeld uitgewerkt:

using System;
using System.Collections.Generic;

namespace Lists
{
    class Program
    {
static void Main(string[] args)
{
    List<User> listOfUsers = new List<User>()
    {
new User() { Name = "John Doe", Age = 42 },
new User() { Name = "Jane Doe", Age = 34 },
new User() { Name = "Joe Doe", Age = 8 },
    };

    for(int i = 0; i < listOfUsers.Count; i++)
    {
Console.WriteLine(listOfUsers[i].Name + " is " + listOfUsers[i].Age + " years old");
    }
    Console.ReadKey();
}
    }

    class User
    {
public string Name { get; set; }

public int Age { get; set; }
    }
}

Onderaan zie je dat we een simpele User klasse definiëren om informatie (naam en leeftijd) bij te houden van een gebruiker. In het bovenste deel van het voorbeeld heb ik de lijst aangepast om de User class te gebruiken in plaats van simpele strings. Ik gebruik een initialisator van verzamelingen om de lijst op te vullen met gebruikers. Je ziet dat de syntax hetzelfde blijft, maar iets complexer is omdat we met een object werken dat complexer is dan een string.

Van zodra de lijst klaar is gebruik ik een for lus om erdoor te lopen. Om te weten hoeveel keer we door de lijst moeten lopen gebruik ik de Count eigenschap van de List. Elke keer we door de lus lopen krijg ik de informatie uit de lijst door gebruik te maken van de indexer van de lijst. Hiervoor gebruiken we de vierkante haakjes syntax (listOfUsers[i]). Zodra ik de informatie heb geef ik de naam en de leeftijd weer.

Items toevoegen, inserten en verwijderen

We weten al hoe we één item kunnen toevoegen aan een lijst, maar er zijn meerdere opties om dit te doen. Met Add voeg je altijd een item toe aan het einde van de lijst, met de Insert methode daarentegen kan je een item toevoegen op een specifieke positie:

List<string> listOfNames = new List<string>()
{
    "Joe Doe"
};
// Insert at the top (index 0)
listOfNames.Insert(0, "John Doe");
// Insert in the middle (index 1)
listOfNames.Insert(1, "Jane Doe");

We instantiëren onze lijst met 1 item er in. Maar dan voegen we 2 extra items toe. Een aan het begin van de lijst en een in het midden. De eerste parameter van de Insert methode is de indexpositie waar we het item willen toevoegen. Let hier wel mee op, als je een item probeert toe te voegen op indexpositie 4 zal je een foutmelding krijgen omdat de lijst minder items bevat dan de index die je meegeeft.

Meerdere items toevoegen

We hebben de Add en Insert methoden voor het toevoegen van 1 item, er zijn ook methoden voor het toevoegen of inserten van meerdere items. Dit zijn de AddRange() en InsertRange() methoden en aanvaarden elk type verzameling die de IEnumerableinterface implementeren als parameter. Dit kan bijvoorbeeld een array van items zijn, of een andere lijst waarvan je de items wil toevoegen of inserten in de huidige lijst.

Als voorbeeld voor de Range() methoden gaan we iets leuk doen. We combineren de AddRange() methode met een initialisator voor verzamelingen om meerdere nieuwe namen toe te voegen aan een bestaande lijst met een enkele statement.

listOfNames.AddRange(new string[]
    {
"Jenna Doe",
"Another Doe"
    });

We maken on-the-fly een array van strings en voegen die onmiddelijk toe als items aan de lijst met namen uit ons vorige voorbeeld.

Items verwijderen

Er zijn 3 methoden te onzer beschikking als we 1 of meerdere items willen verwijderen uit een lijst: Remove(), RemoveAt() en RemoveAll().

De Remove() methode aanvaardt slechts 1 parameter. Het item dat je wil verwijderen. Dit is handig voor lijsten met strings of integers, want je kan gewoon het item dat je wenst te verwijderen invullen. Aan de andere kant, als je een lijst hebt met complexe objecten zou je eerst dat object moeten vinden, zodat je dit dan kan doorgeven aan de Remove() methode. We zien later hoe dit mogelijk is, eerst volgt een simpel voorbeeld hoe je één item kan verwijderen met de Remove() methode:

List<string> listOfNames = new List<string>()
{
    "John Doe",
    "Jane Doe",
    "Joe Doe",
    "Another Doe"
};

listOfNames.Remove("Joe Doe");

De Remove() methode loopt gewoon door de lijst tot hij de eerste instantie vindt van het object dat je hebt opgegeven om te verwijderen, en verwijdert dit dan. De methode verwijdert slecht één instantie, dus als dezelfde naam of hetzelfde cijfer meerdere keren voorkomt in de lijst zijn deze niet allemaal verwijderd. Als je een item opgeeft dat niet bestaat krijg je geen foutmelding, de methode retourneert wel als true als hij in staat was om een item te verwijderen en false als hij niet in staat was om iets te verwijderen.

De RemoveAt() methode gebruikt de index die de lijst toewijst aan de items in de lijst om items te verwijderen. Zo kan je het eerste item in een lijst op volgende manier verwijderen:

listOfNames.RemoveAt(0);

Of het laatste item in de lijst op deze manier:

listOfNames.RemoveAt(listOfNames.Count - 1);

Dit verwijdert opnieuw slechts één item. Je moet ook voorzichtig zijn wanneer je de index meegeeft van het item dat moet verwijderd worden. Als de index buiten de grenzen valt (lager dan 0 of hoger dan het aantal items in de lijst) krijg je een exception. Dus tenzij je heel zeker bent van wat je doet, is het beter om de RemoveAt() methode in te kapselen in een try-catch block om de exception af te handelen (dit wordt in detail uitgelegd verder in deze tutorial). De RemoveAt() methode retourneert niets, dus je zal het aantal items in de lijst moeten controlen voor en na dat je de methode hebt aangeroepen om zeker te zijn of dit succesvol was. Als je natuurlijk zeker bent dat je een index meegeeft die bestaat in de lijst zal RemoveAt() altijd succesvol zijn.

De RemoveAll() methode is de meeste complexe maar ook de meest krachtige van de Remove methoden. Deze methode aanvaard een delegate van een methode als parameter, waarna de methode beslist of een item moet verwijderd worden door true of false te retourneren. Dit laat ons toe om logische expressies te gebruiken om items te verwijderen en kan ook meer dan een item in een keer verwijderen. Delegates worden verder in deze tutorial behandeld, dit is een groot en complex onderwerp. Maar ik wil dat je toch de RemoveAll() methode eens in actie ziet:

List<string> listOfNames = new List<string>()
{
    "John Doe",
    "Jane Doe",
    "Joe Doe",
    "Another Doe"
};

listOfNames.RemoveAll(name =>
{
    if (name.StartsWith("J"))
return true;
    else
return false;
});

In dit voorbeeld gebruiken we een anonieme methode (ook dit is te complex om hier snel uit te leggen maar we gaan er dieper op in later in deze tutorial) als parameter voor de RemoveAll() methode. Onze anonieme methode is redelijk simpel, ze wordt aangeroepen voor elk item in de lijst en heeft een parameter genaamd name wat het huidige item is in de lus. De methode kijkt naar deze naam en controleert of deze begint met "J". Indien dit het geval is wordt true geretourneerd en anders false. The RemoveAll() methode gebruikt dit antwoord (true of false) om te beslissen of een item moet verwijderd worden of niet. Na het uitvoeren van de methode blijft er nog één lid van de Doe familie over: Another Doe.

Lijstitems sorteren

We hebben nu al de hele tijd gewerkt met de items in de lijst in de volgorde waarin we ze hebben toegevoegd. Het kan natuurlijk dat je een lijst wil sorteren op een bepaalde manier. Onze lijst met namen willen we alfabetisch sorteren. De List<T> heeft een Sort() methode die we daarvoor kunnen gebruiken:

List<string> listOfNames = new List<string>()
{
    "John Doe",
    "Jane Doe",
    "Joe Doe",
    "Another Doe"
};
listOfNames.Sort();
foreach (string name in listOfNames)
    Console.WriteLine(name);

Zoals je zal zien bij de output is onze lijst nu alfabetisch gesorteerd. Als je de volgorde wil omdraaien (van Z naar A) kan je na de Sort() methode de Reverse() methode aanroepen.

listOfNames.Sort();
listOfNames.Reverse();

Onze lijst sorteren was niet zo moeilijk, maar dat komt omdat we een lijst met strings hebben en dat het .NET framework exact weet hoe hij twee strings moet vergelijken. Als je dit met een lijst met cijfers probeert zal .NET dit ook zonder problemen kunnen sorteren. Indien je een lijst zou hebben met custom objecten (aangezien List<T> elk type object kan bevatten) kan .NET niet weten hoe hij dat moet vergelijken. Er zijn meerdere oplossing voor de probleem zoals de IComparable interface implementeren of LINQ gebruiken (we bekijken de beiden later nog in deze tutorial). Voorlopig kunnen we een methode voorzien die door de Sort() methode kan aangeroepen worden en weet hoe twee items uit de lijst met elkaar kunnen vergeleken worden:

using System;
using System.Collections.Generic;

namespace ListSort
{
    class Program
    {
static void Main(string[] args)
{
    List<User> listOfUsers = new List<User>()
    {
new User() { Name = "John Doe", Age = 42 },
new User() { Name = "Jane Doe", Age = 39 },
new User() { Name = "Joe Doe", Age = 13 },
    };
    listOfUsers.Sort(CompareUsers);
    foreach (User user in listOfUsers)
Console.WriteLine(user.Name + ": " + user.Age + " years old");
}

public static int CompareUsers(User user1, User user2)
{
    return user1.Age.CompareTo(user2.Age);
}
    }

    public class User
    {
public string Name { get; set; }
public int Age { get; set; }
    }
}

Op deze manier hebben we heel wat code bijgevoegd in ons voorbeeld, maar eigenlijk is het niet zo moeilijk. Als we beneden beginnen zien we een hele simpele User klasse die bestaat uit de naam en de leeftijd. In het midden hebben we een CompareUsers() methode gedeclareerd, deze neemt 2 gebruikers als parameters en retourneert een integer, deze integer zal aangeven als een item "kleiner dan", "gelijk aan" of "groter dan" (-1, 0, 1) is. Deze waarden zullen dan gebruikt worden door de Sort() methode om de items in de lijst te sorteren. In dit geval gebruiken we de leeftijd ter vergelijking, dit geeft ons een lijst van gebruikers gesorteerd op leeftijd.

Samenvatting

Dit was een van de langste hoofdstukken uit deze tutorial, maar hopelijk heb je veel bijgeleerd over lijsten. Want hoe meer je programmeert, hoe meer je zal beseffen hoe belangrijk lijsten en dictionaries zijn. Dictionaries bekijken we in het volgende hoofdstuk.

This article has been fully translated into the following languages: Is your preferred language not on the list? Click here to help us translate this article into your language!