Gå till innehållet

Kapitel 7 - Samlingar och olika variabeltyper

Introduktion till kapitlet

Vi har använt lärt oss att använda arrayer för att spara flera variabler av samma typ i en lista. Det finns fler sätt att spara olika typer av listor på, sådana listor kallas för samlingar. Vi ska i detta kapitel titta närmare på två olika typer av samlingar som heter List och Dictionary. Kapitlet innehåller också en sammanfattning av de olika variabeltyper som vi har stött på hittills och se hur de kan delas in i två olika varianter, referenstyper och värdetyper.

List

En array är inte alltid smidig att använda. Om man inte vet hur många element arrayen ska innehålla, vilket kan vara fallet om den ska fyllas av information som användaren skriver in, så behöver man skapa en array med onödigt stor kapacitet så att den inte blir överfull. Detta problem slipper man när man använder en List samtidigt som List har många andra inbyggda metoder.

Under ytan så innehåller varje List en array, när man lägger till ett element i en List så läggs elementet till i listans array. Om den dolda arrayen är full och du försöker lägga till ytterligare ett element till listan så kommer listan att skapa en ny array med dubbelt så många platser. Därefter så kopieras alla element från den urpsrungliga arrayen till den nya arrayen och då finns det även plats för det nya elementet som du vill lägga till. Allt detta sker under ytan men det kan ända vara bra att känna till att en List egentligen använder sig av en array. En List har också metoder som t.ex. sorterar listan i storleksordning eller som söker igenom listan efter ett specifikt värde.

I exemplet nedan visas hur man skapar en List med heltal. Notera att det sätt som man anger vilken typ listan ska innehålla liknar det sätt som man anger vad man vill ladda in med metoden Content.Load i MonoGame.

List<int> favorittal = new List<int>();
favorittal.Add(150);
favorittal.Add(4);
favorittal.Add(42);
favorittal.Add(100);
favorittal.Add(16);
favorittal.Add(8);
favorittal.Add(23);
favorittal.Add(15);

// Ta bort talet 100 från listan
favorittal.Remove(100);

// Hitta vilket index talet 150 har i listan
// Ta bort talet på detta index
int index = favorittal.IndexOf(150);
favorittal.RemoveAt(index);

// Sortera listan med favorittal
favorittal.Sort();

// Finns talet 16 i listan?
if (favorittal.Contains(16))
{
    Console.WriteLine("Talet 16 finns i listan");
}

Console.WriteLine("Här är alla mina favorittal (for-loop)");
for (int i = 0; i < favorittal.Count; i++)
{
    Console.WriteLine(favorittal[i]);
}

Console.WriteLine("Här är alla mina favorittal (foreach-loop)");
foreach (int tal in favorittal)
{
    Console.WriteLine(tal);
}

I exemplet så läggs några tal till i en lista, notera att man inte behöver ange listans storlek när man skapar den, listans storlek är alltid lika stor som antalet variabler som är lagrade i den. Det man kallar för listans storlek, d.v.s. antalet variabler i listan, behöver alltså inte vara detsamma som storleken av den dolda arrayen som listan använder.

När talen har lagts till i listan så tas två av dem bort på två olika sätt. Det första sättet använder metoden Remove för att ange vilket tal som ska tas bort, om samma tal finns på flera platser i listan tas bara det första av dessa bort. Den andra metoden tar först reda på vilket index som talet 150 har (det första indexet om 150 finns på flera platser) och därefter tas talet på detta index bort från listan. I detta exempel så finns det inte någon fördel med att ta reda på talets index och sedan ta bort det, detta sätt visas för att du ska se hur man kan använda metoden IndexOf som kan vara användbar i andra sammanhang. Något att notera är att när man tar bort ett föremål från en lista så tas detta föremål bort i den underliggande arrayen. Efter att föremålet i den underliggande arrayen har tagits bort så flyttas alla element som fanns efter detta föremål neråt en plats i listan så att det inte ska finnas några ”hål” eller tomma platser mitt i den dolda arrayen. Detta medför att många anrop av Remove kan påverka ett programs prestanda negativt.

Listan sorteras med den inbyggda metoden Sort som kan användas för att sortera listor av t.ex. tal eller text och sedan skrivs alla tal i listan ut, dels med en for-loop och dels med en foreach-loop. En sammanfattning av de metoder och egenskaper som listor har som exemplet använde visas i tabellen nedan. Vi har även tagit med metoden Clear() som tömmer en lista på alla dess element vilket kan vara väldigt användbart.

Metod eller egenskap Beskrivning
Add(T element) Lägger till ett element av variabeltypen T till listan.
Remove(T element) Tar bort elementet av variabeltypen T från listan.
IndexOf(T element) Hittar det lägsta index som ett element
RemoveAt(int index) Tar bort ett elementet med det angivna indexet från listan.
Clear() Tömmer listan på alla dess element
Sort() Sorterar listan i storleks- eller bokstavsordning.
Contains(T element) true om listan innehåller elementet, annars false
Count Antal element i listan

En lista kan alltså användas istället för en array, men hur ska man veta om man bör använda en array eller en List när man behöver lagra många variabler av samma typ? Som regel så bör man alltid använda en List så länge som det inte finns något annat skäl som man kan komma på för att använda en array.

Var hittar man fler av de metoder en List har?

När du skriver punkten efter namnet på en listvariabel i Visual Studio får du upp en lista med förslag på alla metoder som en List har. Du kan också kolla i dokumentationen av C# som Microsoft har gjort, den finns här. Det är bra att träna på att använda dokumentationen av C# eftersom den är väldigt omfattande och hjälpsam när man vill ha reda på mer om någonting.

Uppgift 7.1

Skapa ett program där användaren får skriva in ett valfritt antal städer, användaren ska inte ange hur många städer som hen vill skriva in i början av programmet. Alla städerna ska sparas i en lista med textsträngar. Användaren ska avsluta sin inmatning av städer genom att skriva in en tom rad. Efter att alla städer är inmatade ska listan sorteras i bokstavsordning och därefter skrivas ut.

Lösningstips 7.1

Skapa en string i ditt program, string nyStad = " ". Använd en loop för att läsa in nya strängar från användaren, loopen ska köras så länge som nyStad inte är "". Glöm inte att lägga till using System.Collections.Generic; längst upp i programmet.

Lösningsförslag 7.1

Uppgift 7.2

Skapa ett program där användaren först ska skriva in 5 heltal som sparas i en lista. Därefter ska användaren få skriva in två nya tal. Programmet ska, utan att använda en loop, undersöka om båda talen finns i listan.

Lösningstips 7.2

Använd metoden Contains(T element) två gånger i en if-sats för att undersöka om talen finns i listan.

Lösningsförslag 7.2

Uppgift 7.3

Skapa ett program där användaren får skriva in lite valfri text. Programmet ska, i bokstavsordning, skriva ut varje tecken som förekom i texten med undantag av mellanslag.

Exempelkörning:

Skriv in några ord
god morgon
Här är alla tecken som fanns i dina ord
d
g
m
n
o
r

Lösningstips 7.3

Använd en List<char> för att spara tecknen. Undersök om ett tecken redan finns i listan med hjälp av Contains(T element) innan du lägger till det.

Lösningsförslag 7.3

Dictionary

List, som vi precis använde, är ett exempel på en samling, eller collection på engelska. Det finns flera andra typer av samlingar med olika funktioner och vi ska här titta på ytterligare än, nämligen Dictionary. En List fungerar på flera sätt som en array där vi kan hitta sakerna i listan om vi vet deras index, och dessa index är alltid heltal. En Dictionary är som en lista där vi kan välja använda vilken variabeltyp vi vill som index, t.ex. en string eller en char. Den variabeltyp vi använder i stället för index kallas för nyckel, och det värde som en nyckel leder till kallas för värde. En Dictionary skulle till exempel kunna innehålla följande information.

Nyckel (string) Värde (int)
Everest 8848
K2 8611
Kangchenjunga 8586
Lhotse 8516

Denna tabell, och dictionaryn som tabellen representerar, innehåller namnen på världens fyra högsta berg som nycklar och deras respektive höjder i meter som värden. Genom att använda en dictionary kan man enkelt komma åt det värde som är associerat med en viss nyckel. Vi tittar på detta med ett kodexempel kopplat till tabellen ovan.

Dictionary<string, int> höjder = new Dictionary<string, int>();

höjder["Everest"] = 8848;
höjder["K2"] = 8611;
höjder["Kangchenjunga"] = 8586;
höjder["Lhotse"] = 8516;

// Vilket höjd har Mount Everest?
Console.WriteLine("Nästa rad visar höjden på Mount Everest");
Console.WriteLine(höjder["Everest"]);

// Visar nya mätningar att Everest är lägre än vi trodde? Ändra dictionaryn
höjder["Everest"] = 8847;

// Vilka nyckel-värde-par finns i dictionaryn?
foreach (var item in höjder)
{
    Console.WriteLine($"Berget {item.Key} har höjden {item.Value} meter.");
}

Exemplet ovan visar även hur man kan loopa igenom en dictionary. Eftersom en dictionary inte använder heltalsindex som ligger på rad måste man använda foreach-loopen och inte for-loopen. Det kan också vara värt att påpeka att man inte kan lägga till flera saker i dictionaryn med samma nyckel, däremot kan flera olika nycklar leda till samma värde.

Varför heter det Dictionary?

En dictionary kan användas på samma sätt som en ordbok (dictionary på engelska). En ordbok översätter en string från ett språk till en string på ett annat språk. För att skapa en dictionary som gör detta kan man till exempel skriva

Dictionary<string, string> ordbok = new Dictionary<string, string>();
ordbok["ja"] = "yes";
ordbok["nej"] = "no";
Denna dictionary översätter ord från svenska till engelska.

Precis som List så har Dictionary många inbyggda metoder. Här är några av de som är vanligast att använda:

Metod Beskrivning
ContainsKey(T nyckel) true om dictionaryn innehåller nyckeln, annars false
ContainsValue(T värde) true om dictionaryn innehåller värdet, annars false
Remove(T nyckel) Tar bort den angivna nyckeln variabeltypen T från samt det tillhörande värdet.
Clear() Tömmer dictionaryn på alla dess element

En dictionary kan vara väldigt användbar inom problemlösning och kan förenkla flera av de problem som har funnits med som svåra uppgifter i tidigare kapitel. Det vanligaste är man inte anger elementen i dictionaryn manuellt så som vi gjort ovan, oftast så fyller man i dictionaryn med hjälp av en loop. I exemplet nedan används en dictionary för att räkna hur många gånger olika tecken förekommer i en string.

string text = "apa banan citron";
Dictionary<char, int> antalFörekomster = new Dictionary<char, int>();

foreach (var tecken in text)
{
    if (antalFörekomster.ContainsKey(tecken))
    {
        antalFörekomster[tecken]++;
    }
    else
    {
        antalFörekomster[tecken] = 1;
    }
}

Console.WriteLine("Strängen innehåller följande tecken:");
foreach (var item in antalFörekomster)
{
    Console.WriteLine($"{item.Key} - {item.Value}");
}

När programmet körs skrivs följande text ut

Strängen innehåller följande tecken:
a - 4
p - 1
  - 2
b - 1
n - 3
c - 1
i - 1
t - 1
r - 1
o - 1
Att räkna och jämföra antal förekomster av olika tecken i strängar har vi jobbat med i tidigare uppgifter och i vissa fall kan lösningarna bli enklare och mer eleganta med hjälp av Dictionary.

Uppgift 7.4

Skapa ett program där som ska kunna översätta orden hej, dator, tangentbord och mus till engelska med hjälp av en dictionary. Be användaren skriva in ett av dessa ord och skriv sedan ut översättningen på engelska med hjälp av dictionaryn.

Lösningsförslag 7.4

Uppgift 7.5

Skapa ett program där användaren får skriva in en mening. Programmet ska skriva ut alla ord som förekommer exakt 2 eller 3 gånger i meningen.

Lösningstips 7.5

Använd Split för att dela upp meningen till en array. Skapa en dictionary som räknar hur många gånger varje ord förekommer i meningen.

Lösningsförslag 7.5

Olika variabeltyper

För att bättre förstå hur C# fungerar så ska vi studera de olika typer av variabler som finns lite djupare. Vi har hittills använt många olika variabeltyper som t.ex. int, string, double, Random och arrayer. Alla variabeltyper i C# kan sorteras in i en av två olika grupper: värdetyper och referenstyper. De flesta variabeltyper som vi har jobbat med hittills är värdetyper, men arrayer, listor och dictionary är referenstyper och vi kommer dessutom att stöta på fler referenstyper snart så det är bra att veta vad som skiljer dem åt.

Viktig teori

Detta avsnitt har inga programmeringsuppgifter i slutet men innehåller teori om hur olika variabeltyper fungerar. Det är väldigt viktigt att förstå skillnaden på värdetyper och referenstyper om man ska bli en bra programmerare.

Värdetyper

Variabeltyper som t.ex. int, double och bool är några exempel på värdetyper. Värdetyper är variabeltyper som sparar själva variabelns värde i på variabelns plats i datorminnet. Det kan kanske låta självklart att det är så eller svårt att veta vad som skulle sparas i variabeln annars, men referenstyper fungerar på ett lite annorlunda sätt som du snart kommer få se. Vi ska se hur värdetyper och speciellt kopiering av värdetyper fungerar i följande exempel. Variablerna a och b som är med i programmet skrivs ut flera gånger under programmets körning för att du ska kunna se vilka värden de har.

int a = 8;
int b = a;
Console.WriteLine($"a: {a}, b: {b}");

a = 5;
Console.WriteLine($"a: {a}, b: {b}");

ÄndraVärde(a);
Console.WriteLine($"a: {a}, b: {b}");


void ÄndraVärde(int tal)
{
    tal = 3;
}

I det första stycket av koden så skapas variablerna a och b. Variabeln b ges samma värde som variabel a, i detta fall 8, och får då en egen kopia av talet 8 sparat i sig. Värdet av båda variablerna skrivs ut av programmet.

Variabelnamn Värde
a 8
b 8

Variabeln a ges ett nytt värde, talet 5. Variablerna a och b är inte ihopkopplade även om vi tidigare skrev att b skulle vara lika med a. Värdet av b blev just då lika med värdet av a vilket gjorde att b fick värdet 8, men när a får ett nytt värde senare i programmet så kommer värdet av b inte att ändras.

Variabelnamn Värde
a 5
b 8

I det sista stycket i programmet så anropas metoden ÄndraVärde med variabeln a som argument. När detta sker så kopieras värdet av argumentet till metodens parameter, det vill säga värdet av variabeln a kopieras till variabeln tal. När metoden körs så ändras värdet av variabeln tal till 3 men detta påverkar inte variabeln a.

Variabelnamn Värde
a 5
b 8

Det finns likheter med hur variabeln a fungerade både när b fick värdet av a och när metoden ÄndraVärde anropades med a som argument. I båda fallen så kopierades värdet av a till en ny variabel, antingen b eller tal. När dessa variabler sedan ändrades så ändrades inte värdet av variabeln a. I exemplet så var variablerna av typen int, men det hade fungerat likadant för alla värdetyper.

Referenstyper

Variabeltyper som inte är värdetyper är istället referenstyper. Sådana typer sparar inte själva värdet av variabeln inuti variabelns plats i datorminnet, istället innehåller variabeln en referens till var i minnet som information finns. Alla arrayer är referenstyper och vi ske se hur det påverkar programmet nedan som liknar exempelprogrammet som handlade om värdetyper.

int[] a = { 5, 10, 15 };
int[] b = a;
Console.WriteLine($"a[1]: {a[1]}, b[1]: {b[1]}");

b[1] = 20;
Console.WriteLine($"a[1]: {a[1]}, b[1]: {b[1]}");

ÄndraVärde(a);
Console.WriteLine($"a[1]: {a[1]}, b[1]: {b[1]}");


void ÄndraVärde(int[] talArray)
{
    talArray[1] = 25;
}

I början av programmet skapas en array och sparas i variabeln a. Vad som egentligen händer är att på någon plats i datorns minne så skapas själva arrayen av heltal som innehåller värdena 5, 10 och 15, men själva arrayen sparas inte i variabeln a. Det som sparas i variabeln a är istället adressen till den plats i minnet där arrayen finns, vilket också kallas för en referens till den plats där arrayen är. Det går inte att veta vilken plats i minnet som arrayen kommer att skapas på när vi skriver koden, det bestäms först när programmet kör. Om vi antar att arrayen skulle skapas på minnesplats A20 när programmet körs så är värdet av a A20, alltså

Variabelnamn Värde
a A20

På platsen i datorns minne med adressen A20 finns själva arrayen som har följande innehåll.

Index Värde
0 5
1 10
2 15

När variabeln b deklareras och tilldelas ett värde så får den samma värde som variabeln b, nämligen A20. Både a och b har nu samma värde, de har adressen till samma array som finns på minnesplats A20. Man säger också att de refererar till samma array.

Variabelnamn Värde
a A20
b A20

När värdet av a[1] ska skrivas ut med Console.WriteLine så kommer programmet att gå till den array som finns på adressen som är sparad i a, arrayen på minnesplats A20. Den hämtar värdet som finns på index 1 i denna array, värdet 10, och skriver ut det. Detsamma sker när b[1] ska skrivas ut, och eftersom värdet hämtas från samma array båda gångera så skrivs talet 10 ut två gånger.

När koden b[1] = 20 körs så kommer programmet att gå till den array som finns på minnesplats A20 och ändra värdet på index 1 till 20. Värdet av variablerna a och b har inte ändrats någonting, de har fortfarande adressen till samma array som tidigare.

Variabelnamn Värde
a A20
b A20

Däremot så har själva arrayen som finns på minnesplats A20 ändrats, den har nu följande värden.

Index Värde
0 5
1 20
2 15

Eftersom a och b fortfarande refererar till samma adress kommer både a[1] och b[1] vara 20. När metoden ÄndraVärde anropas med variabeln a som argument så kommer värdet av a att kopieras till parametern talArray. Detta innebär att även talArray får värdet A20.

Index Värde
0 5
1 25
2 15

När sedan talArray[1] ändras så är det arrayen på minnesplats A20 som kommer att förändras. När metoden har kört klart och a[1] och b[1] ska skrivas ut en sista gång så kommer deras värden att ha förändrats till 25.

Hur skulle man då ha gjort om man ville att variabeln b skulle referera till en ny array som hade samma innehåll som arrayen a? Man hade i detta fall kunnat göra det med

int[] b = { 5, 10, 15 };

men det är inte alltid så att man vet värdet av alla element i arrayen man vill kopiera. En mer allmän metod hade varit att skapa en array med samma längd som a genom att skriva

int[] b = new int[a.Length];

och sedan gå igenom hela arrayen som a hänvisar till med en loop och kopiera över varje element till motsvarande index i arrayen som b hänvisar till. Det är dock inte vanligt att man vill göra en sådan kopiering av en array så försök att undvika det om det går.

Värdetyp eller referenstyp?

Om du håller musen över en variabeltyp i Visual Studio så får man information om variabeltypen i en ruta som dyker upp. Om variabeltypen är en struct eller enum så är den en värdetyp, är den en class så är den en referenstyp.

En array är alltid en referenstyp oavsett om arrayen innehåller en värdetyp eller referenstyp.

På detta sätt kan man se att t.ex. både int och bool tillhör kategorin struct, alltså är de värdetyper. Variabeltypen Random är en class och är därmed en referenstyp.

Du har nu fått se hur värdetyper och och referenstyper skiljer sig åt med hjälp av två snarlika program. För att verkligen förstå hur dina program fungerar och varför de ibland inte gör som du vill så måste man veta skillnaden mellan värdetyper och referenstyper, och det kan vara bra att i framtiden gå tillbaka till detta avsnitt för att repetera hur de skiljer sig åt. Tills vidare så ska du komma ihåg att alla arrayer är referenstyper, vi kommer att stöta på fler referenstyper senare i boken.

Referenstyper som argument

I det förra avsnittet fick du se att man kan använda arrayer som argument när man anropar en metod och vad man behöver tänka på när man använder anropar metoder med en referenstyp. Vi studerar arrayer som argument i ytterligare ett exempel. Kom ihåg att en array alltid är en referenstyp oavsett vilken typ av variabler som arrayen innehåller.

string[] namn = { "Anna", "Bob", "Clara", "Bob" };
Console.WriteLine(namn[0]);
BytFörstaOchSista(namn);
Console.WriteLine(namn[0]);
int antalBob = SökEfterSträng("Bob", namn);
Console.WriteLine($"Antal Bob: {antalBob}");

void BytFörstaOchSista(string[] textArray)
{
    string temp = textArray[0];
    textArray[0] = textArray[textArray.Length - 1];
    textArray[textArray.Length - 1] = temp;
}

int SökEfterSträng(string sökSträng, string[] sökArray)
{
    int antalPassande = 0;
    foreach (string text in sökArray)
    {
        if (text == sökSträng)
        {
            antalPassande++;
        }
    }
    return antalPassande;
}

I exemplet så skapas en array med fyra namn, ett av dessa förekommer två gånger. När Console.WriteLine anropas första gången skrivs namnet Anna ut. Innan Console.WriteLine anropas igen så anropas metoden BytFörstaOchSista med arrayen namn som argument. Denna metod byter plats på det första och sista elementet i arrayen och eftersom alla arrayer är referenstyper så påverkas den array som variabeln namn refererar till. Detta innebär att nästa Console.WriteLine kommer att skriva ut namnet Bob som tidigare låg på sista plats i arrayen. Vill man ändra en array som man skickar som argument till en metod så går det bra, man behöver inte skicka en ny förändrad array som svar vilket man hade behövt göra med en värdetyp.

Metoden SökEfterSträng letar igenom en array med strängar efter en viss söksträng och returnerar sedan hur många gånger som söksträngen fanns i arrayen. När metoden anropas i exemplet så söks arrayen igenom efter namnet Bob och den kommer då att returnera svaret 2. Denna metod visar att man kan använda metoder utan att påverka arrayens innehåll, denna metod skickar istället tillbaka ett svar om arrayen.

Uppgift 7.6

Skapa ett program som innehåller en metod som heter Summa. Metoden ska ha en parameter som är en double-array, den ska returnera summan av alla tal inuti arrayen.

Lösningsförslag 7.6

Uppgift 7.7

Skapa ett program som innehåller en metod som heter Medelvärde. Metoden ska ha en parameter som är en List<int>, den ska returnera medelvärdet av alla heltal i listan. Testa att din metod fungerar med en lista som endast innehåller talen 1 och 2.

Lösningstips 7.7

Tänk på att beräkningar med enbart heltal ger heltal som svar. Om du låter variabeln som beräknar summan av hela arrayen vara en double istället för en int så kan metoden fungera, alternativt så kan du konvertera ett heltal till en double vid en beräkning för att svaret ska bli en double.

Lösningsförslag 7.7

Uppgift 7.8

Skapa ett program som innehåller en metod som heter Vänd. Metoden ska ha en parameter som är en array av strängar. Metoden ska vända en array så att elementen hamnar i omvänd ordning, det första elementet ska bli sist, det andra näst sist o.s.v.

Lösningstips 7.8

Byt plats på elementet med index 0 och elementet med index (längd - 1), elementet med index 1 ska byta plats med elementet med index (längd - 2) o.s.v. Använd en temp-variabel vid bytet.

Lösningsförslag 7.8

Variablers standardvärden

Om en variabel deklararas, d.v.s. skapas, men inte tilldelas något värde så kommer den att ha standardvärdet för den variabeltyp som den är. Det är inte möjligt att använda en lokal variabel som inte har blivit tilldelad ett värde i C#, men man kan göra det med en klassvariabel. Alla olika taltyper som int och double har standardvärdet 0 medan bool har standardvärdet false, i de flesta fall så har värdetyper ett standardvärde som på något sätt motsvarar talet 0.

Mer viktig teori

Precis som avsnittet om variabeltyper så har inte detta avsnitt några uppgifter. Trots detta så innehåller avsnittet viktig teoretiskt information som alla bra programmerare behöver veta för att förstå varför programmen gör eller inte gör som programmeraren vill, och utan dessa kunskaper kommer du få problem med kommande projektuppgifter.

Alla variabeltyper som är referenstyper har ett speciellt värde som standardvärde, ett värde som heter null. En referenstyp innehåller som vi tidigare sett en adress till var i datorns minne själva innehållet i variabeln finns. Värdet null innebär att variabeln inte har någon adress till något ställe i datorminnet. Om man försöker hämta information om eller göra någonting med en variabel som har värdet null så kraschar programmet eftersom det inte vet var i datorns minne det ska gå för att hämta informationen.

Även string är en referenstyp. Strängar är ett specialfall som egentligen är en referenstyp men av olika skäl är gjorde att fungera som värdetyper i många olika fall. Det man behöver tänka på med strängar är att ett program kan krascha om man försöker göra någonting med en sträng som inte har tilldelats ett värde. I övriga avseenden fungerar strängar som värdetyper.

En bra vana är att alltid tilldela variabler ett värde när du deklarerar dem för att undvika problem med null. Det är dock inte alltid möjligt att direkt tilldela en variabel ett värde, t.ex. när man skapar en array. I exemplet nedan så ges själva arrayvariabeln textArray ett värde eftersom en ny array med 5 strängar skapas, men varje sträng i själva arrayen får standardvärdet null. När programmet försöker gå igenom arrayen med en foreach-loop så kommer det att krascha när den första strängen i arrayen ska undersökas eftersom den är null.

string[] textArray = new string[5];

foreach (string text in textArray)
{
    if (text.Length == 3)
    {
        Console.WriteLine("Strängens längd var 3");
    }
}

Notera att programmet inte skulle krascha om man bara försökte skriva ut talArray eller text med Console.WriteLine, om man försöker skriva ut en variabel som har värdet null så skrivs ingenting ut.

För att undvika det problem som finns i programmet ovan så är det en bra idé att gå igenom hela arrayen med en loop och ge varje sträng ett värde direkt efter att arrayen har skapats, i detta exempel hade följande kod kunnat göra detta.

for (int i = 0; i < textArray.Length; i++)
{
    textArray[i] = "";
}

Problemet med null uppstår bara med referenstyper, hade arrayen i exemplet bestått av t.ex. int-variabler så hade programmet inte kunnat krascha p.g.a. ett null-värde.

Blandade uppgifter till kapitel 7

Uppgift 7.9

Skapa ett konsolprogram där användaren ska få skriva in namn. Användaren ska inte behöva ange hur många namn som ska skrivas in när programmet börjar. Användaren ska få mata in nya namn ända tills hen skriver en tom rad. Alla de inmatade namnen ska skrivas ut i omvänd bokstavsordning.

Lösningstips 7.9

När du ska skriva ut namnen i omvänd bokstavsordning så kan du sortera listan som vanligt och sedan gå igenom listan bakifrån, d.v.s. börja på det sista indexet med en for-loop och räkna nedåt.

Lösningsförslag 7.9

Uppgift 7.10

Skapa ett program som har en metod som heter Max. Metoden ska ha en List<int> som parameter och ska returnera det största talet som finns i listan.

Lösningstips 7.10

I metoden kan du börja med att skapa en variabel som heter max och ge den värdet av det första talet i listan. Undersök sedan med en loop om det finns något annat tal som är större.

Lösningsförslag 7.10

Uppgift 7.11

Tabellen nedan visar storleken av fyra länder mätt i enheten hundratusentals kvadratkilometer.

Land Area (10^5 km^2)
Sverige 450
Norge 385
Danmark 43
Finland 338

Skapa ett program där användaren får skriva ett av dessa länders namn. Programmet ska med hjälp av en Dictionary ange storleken på landet.

Lösningstips 7.11

Använd en Dictionary<string, int> med ländernas namn som nycklar och deras storlekar som värden.

Lösningsförslag 7.11

Uppgift 7.12

Skapa ett program som innehåller en metod som heter FinnsTecknetIAllaSträngar. Metoden ska ha två parametrar, en string-array samt en char, och den ska undersöka om char-parametern finns i varje sträng i string-arrayen. Metoden ska svara med true eller false.

Om metoden till exempel anropas med arrayen { "hej", "nej", "ja" } och tecknet j ska den returnera true, men om man i stället anropar med samma lista och tecknet e ska den returnera false.

Lösningstips 7.12

Använd nästlade loopar för att gå igenom varje sträng i listan tecken för tecken. Undersök om någon sträng INTE innehåller tecknet, då kan du returnera false. Om du inte hittar någon som INTE innehåller tecknet så kan du returnera true.

Lösningsförslag 7.12

Uppgift 7.13

Skapa ett konsolprogram där användaren ska få skriva in sina senaste månadslöner. Användaren ska inte behöva ange hur många månadslöner som ska skrivas in när programmet börjar. Användaren ska fortsätta att skriva in månadslöner till hen skriver in lönen 0, talet 0 avslutar endast inmatningen och ska inte räknas som en månadslön. Beräkna och skriv ut användarens medel- och medianlön.

Lösningstips 7.13

Sortera listan innan du ska ta reda på medianlönen. Glöm inte att först undersöka om det finns ett jämnt eller udda antal löner i listan, detta påverkar hur du ska beräkna medianen. För att undersöka om t.ex. i är jämnt, alltså delbart med 2, så ska uttrycket i % 2 == 0 vara sant.

Lösningsförslag 7.13

Uppgift 7.14

Skapa ett konsolprogram som ska beräkna kostaden för användarens handlingslista. Användaren ska skriva in tre rader med information när programmet kör. Den första raden ska vara namnen på produkterna hen ska handla, t.ex. banan citron. Nästa rad ska innehålla styckpriset för varje matvara som skrevs in på första raden, t.ex. 5 8 om bananer kostar 5 kr/st och citroner 8 kr/st. Sista raden ska vara användarens handlingslista, om det står banan banan citron banan citron betyder det att man ska köpa 3 bananer och 2 citroner. Programmet ska skriva ut den totala kostnaden att köpa det som står i handlingslistan. En körning av programmet skulle kunna se ut så här:

Skriv in namn på matvaror
banan citron
Skriv in matvarornas priser
5 8
Skriv in din handlingslista
banan banan citron banan citron
Priset för handlingslistan är 31
Lösningstips 7.14

Använd en Dictionary för att spara priset för varje matvara.

Lösningsförslag 7.14

Uppgift 7.15

Skapa ett program som har en metod som heter FinnsIBåda. Metoden ska ha två string-arrayer som parametrar. Metoden ska undersöka vilka strängar som finns i båda arrayerna och returnera en ny array som innehåller dessa strängar. Varje sträng ska endast förekomma en gång i den returnerade arrayen.

För testning så kan du använda följande info: om metoden anropas med de två arrayerna

{ "a", "b", "b", "c", "hej" }
{ "hej", "a", "a", "b", "programmering" }

så ska den returnera

{ "a", "b", "hej" }
Lösningstips 7.15

Skapa en temporär array med samma längd som den första parameterarrayen. Fyll denna array med alla strängar som finns i båda parameterarrayerna. Skapa därefter en ny kopia med lagom längd som du flyttar alla strängar från temporära arrayen till.

Lösningsförslag 7.15

Uppgift 7.16

I denna uppgift ska du skapa ett program som kan avkoda hemliga meddelanden med hjälp av koder. Först ska användaren få skriva in hur många koder som hen vill ange. Därefter ska man ange alla sina koder på formen "X Y", vilket innebär att alla gånger X finns med i det hemliga meddelandet så ska det bytas ut mot Y. Slutligen ska användaren skriva in ett hemligt meddelande som ska avkodas med hjälp av de koder som har matats in.

Ett exempel på en körning av programmet skulle kunna se ut så här:

Hur många koder vill du skriva in?
5
c b
d a
b z
e i
f c
Skriv in ditt hemliga meddelande
pebfd
Här är ditt avkodade meddelande:
pizza
Vi går igenom det hemliga meddelandet pedcd tecken för tecken och ser hur det har avkodats.

  • Det finns ingen kod som innehåller p, så det behöver inte ändras.
  • Enligt en av koderna ska alla e bytas till i, så det andra tecknet blir i.
  • Alla b bytas till z, så det tredje tecknet blir z.
  • Alla f ska bytas till c. Eftersom det finns en regel för c så måste detta sedan bytas till b. Eftersom det också finns regel för b måste detta bytas till z. Detta leder slutligen till att det fjärde tecknet blir ett z.
  • Alla d ska bytas till a, så det femte tecknet blir ett a.
Lösningstips 7.16

Skapa en Dictionary som innehåller alla avkodningsregler. När du avkodar ett tecken måste du fortsätta avkodningen så länge som det avkodade tecknet också finns som nyckel i dictionaryn.

Lösningsförslag 7.16