Beginner 5
Forberedelse
Et map er en datastruktur der associerer hvert element fra én mængde af værdier med netop én element i en anden mængde af værdier. Den første mængde er vores nøgler (en: keys) og den anden er disse nøglers værdier (en: values).
Arbitrære nøgler
Lad os prøve at bruge et map til at repræsentere forholdet mellem forkortelser på måneder og disse måneders længder:
leap_year = false
month_lengths = %{
"jan" => 31,
"feb" => 28 + if leap_year do 1 else 0 end,
"mar" => 31,
"apr" => 30,
"maj" => 31,
"jun" => 30,
"jul" => 31,
"aug" => 31,
"sep" => 30,
"okt" => 31,
"nov" => 30,
"dec" => 31,
}
Vi kan nu med Map.get
funktionen slå en vilkårlig måneds længde op:
"Oktober er #{Map.get(month_lengths, "okt")} dage lang"
En variant af denne funktion kan gives en default værdi som kommer i spil hvis nøglen ikke findes:
"October er #{Map.get(month_lengths, "oct", "")} dage lang"
Vi kan tilføje en association:
month_lengths = Map.put(month_lengths, "oct", 31)
"October er #{Map.get(month_lengths, "oct", "")} dage lang"
Vi kan spørge om en nøgle eksisterer i vores map:
Map.has_key?(month_lengths, "oct")
I ovenstående har vi brugt strene som keys, men det kunne være hvad som helst. Det kunne eksempelvis være tuples:
month_lengths = %{
{:da, "jan"} => 31,
{:da, "feb"} => 28 + if leap_year do 1 else 0 end,
{:da, "mar"} => 31,
{:da, "apr"} => 30,
{:da, "maj"} => 31,
{:da, "jun"} => 30,
{:da, "jul"} => 31,
{:da, "aug"} => 31,
{:da, "sep"} => 30,
{:da, "okt"} => 31,
{:da, "nov"} => 30,
{:da, "dec"} => 31,
{:en, "jan"} => 31,
{:en, "feb"} => 28 + if leap_year do 1 else 0 end,
{:en, "mar"} => 31,
{:en, "apr"} => 30,
{:en, "may"} => 31,
{:en, "jun"} => 30,
{:en, "jul"} => 31,
{:en, "aug"} => 31,
{:en, "sep"} => 30,
{:en, "oct"} => 31,
{:en, "nov"} => 30,
{:en, "dec"} => 31,
}
Bemærk: Det kunne faktisk være en kombination.
Atomer som nøgler
Et ofte anvendt specialtilfælde er når alle nøglerne er atomer:
month_lengths = %{
jan: 31,
feb: 28 + if leap_year do 1 else 0 end,
mar: 31,
apr: 30,
maj: 31,
jun: 30,
jul: 31,
aug: 31,
sep: 30,
okt: 31,
nov: 30,
dec: 31,
}
Da kan vi tilgå de enkelte nøglers værdier med .
operatoren:
month_lengths.okt
Til og fra lister
Maps kan håndteres som lister:
month_lengths
|> Enum.map(fn {key, value} -> "#{key} har værdien #{value}" end)
Her er hvert element der håndteres af den anonyme funtion en tuple, og det pattern matches der på.
Det kan vi udnytte til at gå den anden vej:
l = [
{"jan", 31},
{"feb", 28 + if leap_year do 1 else 0 end},
{"mar", 31},
{"apr", 30},
{"maj", 31},
{"jun", 30},
{"jul", 31},
{"aug", 31},
{"sep", 30},
{"okt", 31},
{"nov", 30},
{"dec", 31},
]
Map.new(l)
Øvelse
Lad os tage et helt tilfældigt år som udgangspunkt:
year = 2024
Reglerne om skudår siger, at
“This extra leap day occurs in each year that is a multiple of 4, except for years evenly divisible by 100 but not by 400”
Lav nu en erklæring af variablen leap_year?
der afhænger af værdien af variablen year
og er sand hvis der skal insættes en ekstra dag i Februar.
Opret i følgende kode celle et modul der hedder Calendar
.
I dette modul laver du:
-
en funktion der hedder
generate_month_lengths
som tager et år som parameter, og på baggrund af dette år producere et map for dette år. -
en funktion der hedder
generate
som tager to parametre:min_year
ogmax_year
. Den gennemløber alle årene i mellem disse (inklusiv begge), og for hvert år kalder dengenerate_month_lengths
. Resultatet af dette funktionskald bruges til at konstruere et map sådan at man først kan slå et år op og få resultatet af kaldet tilgenerate_month_lengths
. Dette map fra måned til årskalender returneres.
Anvend i den efterfølgende kode celle funktionen generate
til at producere en kalender for årene 0 til 3000.
Næste trin …
Når du er færdig går du til næste øvelse her.