Uke 9 - Dict ============ Denne uken skal vi se på en ny datastruktur, *dict*, som er brukt ofte for å lagre strukturert data. Først, les gjennom https://automatetheboringstuff.com/2e/chapter5/ frem til "Pretty Printing", og se på "Practice Questions 1-7" Eksempler --------- Eksempel 1 .......... Her er et eksempel på en dictionary i Python. I dette eksemplet sier den hvilket husdyr ulike personer har. Last ned filen her: :download:`eksempel_1.py`, og kjør koden. Er navnet 'keys' eller 'values' i ``pet``? Er dyret 'keys' eller 'values' i ``pet``? Hva gjør koden ``pet['Alice']``? Hva gjør koden ``pet['Xavier'] = 'Alien'``? Hvorfor blir det feil i den siste linjen? .. literalinclude:: eksempel_1.py .. _uke_09_oppgave_1: Oppgave 1 ......... I filen ``uke_09_oppg_1.py``, **lag en handleliste og skriv ut den på skjermen**. Handlelisten skal være en dict med varer som keys og antall som values. Varene er: .. code-block:: text 2 brød 3 pizza 10 poteter 1 kaffe 1 ost 14 epler .. note:: Skriv svaret i det følgende formatet: .. code-block:: python handleliste = { ... din kode her ... } print(handleliste) .. _uke_09_oppgave_2: Oppgave 2 ......... Collatz-sekvensen er definert som følger: 1. Start med et tall :math:`n`. 2. Hvis :math:`n` er jevn så er neste tall :math:`\frac{n}{2}`, ellers så er neste tall :math:`3n+1`. 3. Repetere steg 2 med de nye tallene ende til du får tallet :math:`1`. Her er en funksjon som beregner Collatz-sekvensen helt til vi får :math:`1`, gitt en startverdi :math:`n`: .. code-block:: python def collatz_sequence(n): sequence = [n] while n > 1: if n % 2 == 0: n = n // 2 else: n = 3 * n + 1 sequence.append(n) return sequence I filen ``uke_09_oppg_2.py``, skriv en funksjon som heter ``first_ten_collatz()`` som bruker ``collatz_sequence()`` til å beregne Collatz-sekvensen til tallene 1-10 og siden returnerer sekvensene i en dictionary hvor startverdiene er nøkklene. For eksempel ser starten på dictionarien slik ut: .. code-block:: python {1: [1], 2: [2, 1], 3: [3, 10, 5, 16, 8, 4, 2, 1], 4: [4, 2, 1], ...} Eksempel 2 .......... Vi kan bruke ``.keys()``, ``.values()`` og ``.items()`` sammen med en for-løkke. Last ned filen her: :download:`eksempel_2.py`, og kjør koden. Hva looper vi over når vi bruker en for-løkke med ``.keys()``? Hva om vi bruker ``.values()``? Hva om vi bruker ``.items()``? Hva skjer i den siste løkken? .. literalinclude:: eksempel_2.py .. _uke_09_oppgave_3: Oppgave 3 ......... I denne oppgaven skal vi jobbe med ``week_precip`` og ``week_temps`` definert her: .. code-block:: python week_precip = { "monday": 0, "tuesday": 0.7, "wednesday": 0, "thursday": 4.7, "friday": 10 } week_temps = [7.0, 8.0, 10.0, 9.0, 10.0] I filen ``uke_09_oppg_3.py``, skriv ut nøklene, verdiene og nøkkel/verdi-par for ``week_precip``, og listeverdiene og index/verdi par for ``week_temps``. Eksempelkjøring: .. code-block:: text Dictionary Keys: monday tuesday wednesday thursday friday Dictionary Values: 0 0.7 0 4.7 10 Dictionary keys/value: monday 0 tuesday 0.7 wednesday 0 thursday 4.7 friday 10 List values: 7.0 8.0 10.0 9.0 10.0 List indices/value: 0 7.0 1 8.0 2 10.0 3 9.0 4 10.0 Eksempel 3 .......... Metoden ``.get()`` brukes til å finne ut verdien til en gitt nøkkel. Forskjellen mellom ``.get()`` og å bruke ``[]`` er at vi ikke får KeyError om nøkkelen ikke finnes da vi bruker ``.get()``. Last ned filen her: :download:`eksempel_3.py`, og kjør koden. Skjønner du hva som skjer? .. literalinclude:: eksempel_3.py .. _uke_09_oppgave_4: Oppgave 4 ......... Vi ser for oss at følgende dictionary representerer varebeholdningen i en bokhandel. Nøklene er titler og verdiene er antall bøker: .. code-block:: python in_storage = { "Ancillary Justice": 1_046, # vi kan bruke _ i tall, den blir ignorert "The Use of Weapons": 372, "1984": 5_332, "The Three-Body Problem": 523, "A Fisherman of the Inland Sea": 728, } I filen ``uke_09_oppg_4.py``, skriv et program som ta brukerinput en boktittel (bruk ``input()`` for dette) og brukes ``.get()`` **i en løkke** for å finne ut hvor mange eksemplarer av boka vi har. Programmet skriver ut stringen som sier hvor mange eksemplarer av boken vi har, f.eks: ``Vi har 5332 av "1984"``. Hvis boka **ikke** er på lager skal programmet skrive ut stringen ``Vi har 0 av [book_tittel]``. Kjør løkken frem til vi får en tom streng som tittel. Da burde programmet skriver ut stringen ``Ha det!``. Eksempelkjøring: .. code-block:: python >>> Tittel: 1984 Vi har 5332 av "1984" >>> Tittel: A Fire Upon the Deep Vi har 0 av "A Fire Upon the Deep" >>> Tittel: Automate the Boring Stuff with Python Vi har 0 av "Automate the Boring Stuff with Python" >>> Tittel: Ha det! Eksempel 4 .......... Vi kan bruke alle 'immutable data types' som keys i en dictionary. Husker du hvilke datatyper er immutable? I eksemplet her bruker vi heltall og strenger. Last ned filen her: :download:`eksempel_4.py`. Hva gjør koden? Kjør koden og se om det var riktig. Hvordan ser ``number_name`` ut på slutten av kjøringen? .. literalinclude:: eksempel_4.py .. _uke_09_oppgave_5: Oppgave 5 ......... I denne oppgaven skal vi bruke en dictionary med informasjon om værstasjoner: .. code-block:: python weather_stations = { "Bergen" : { "Wind speed": 3.6, "Wind direction": "northeast", "Precipitation": 5.2, "Device": "WeatherMaster500" }, "Trondheim" : { "Wind speed": 8.2, "Wind direction": "northwest", "Precipitation": 0.2, "Device": "ClimateDiscoverer3000" }, "Svalbard" : { "Wind speed": 7.5, "Wind direction": "southwest", "Precipitation": 1.1, "Device": "WeatherFinder5.0" }, } I filen ``uke_09_oppg_5.py``, lag et program som skriver ut værrapporten fra alle værstasjonene enligt følgende eksempel: .. code-block:: python The weather in Bergen: The wind speed is 3.6 m/s in the northeast direction and the precipitation is 5.2 mm. The measurement was done using the WeatherMaster500 weather station. The weather in Trondheim: ... Eksempel 5 .......... Metoden ``.setdefault()`` returnerer verdien til en gitt nøkkel om den finnes i dictionarien. Om den ikke finnes så putter den inn en slik nøkkel med enten verdien ``None`` eller med en verdi vi gir, og returnerer så verdien som er blitt satt inn. Du kan lese om ``.setdefault()`` `i Pythons dokumentasjon `_. Last ned filen her: :download:`eksempel_5.py` og kjør koden. Skjønner du hva som skjer? .. literalinclude:: eksempel_5.py .. _uke_09_oppgave_6: Oppgave 6 ......... I denne oppgaven skal vi gjøre det samme som i Oppgave 4, men litt annerledes. I filen ``uke_09_oppg_6.py``, gjør detsamme som i Oppgave 4, men hvis brukeren spør om en bok som ikke er på lager skal vi "kjøpe inn" 10 og legge til boka i ``in_storage`` med 10 eksemplarer. Eksempelkjøring: .. code-block:: python >>> Tittel: 1984 Vi har 5332 av "1984" >>> Tittel: Automate the Boring Stuff with Python Vi har 10 av "Automate the Boring Stuff with Python" >>> Tittel: Ha det! **Tips:** bruk `setdefault() `_ Eksempel 6 .......... En dictionary kan f.eks brukes for å holde rede på hvor mange vi har av forskjellige ting. Her bruker vi dictionaries til å telle hvor mange ganger vi bruker ulike bokstaver og ord i begynnelsen av 'Alice in Wonderland'. Last ned filen her: :download:`eksempel_6a.py`, og kjør koden. Skjønner du hva som skjer? I slutten av koden finner vi de 5 vanligste ordene. Prøv å bruk 'option 2' i stedet. Som vanlig kan du finne informasjon om hvordan ``sorted()`` fungerer `i Pythons dokumentasjon `_. .. note:: Husk at du kan bruke søkeordargumenter med funksjonene dine og Pythons innbygde funksjoner, f.eks ``sorted()`` Last ned filen her: :download:`eksempel_6b.py`, og kjør koden. Denne eksemplen er med lister, men du kan også bruke med dictionarys. .. literalinclude:: eksempel_6b.py Se også i koden på variabelen ``sorted_result`` -- dette er en smart bruk av søkeordargumenter for å sortere dictionarien din. .. literalinclude:: eksempel_6a.py Eksempel 7 - set ................ En relatert datatype er ``set``, som er en usortert samling av elementer. Vi kan konstruere dem i Python med ``{}`` (uten ``:``) eller ``set()``. *I mengder finnes det kun én av hvert verdi og det finnes ingen orden mellom verdiene.* Vi kan gjøre samme ting med mengder i Python som vi kan i mengdelære i matematikk. For eksempel kan vi finne ut unionen (elementer som finnes i én eller begge set), snittet (elementer som er felles) og differensen (elementer som ikke finnes i det andre set) mellom mengder, eller om en mengde er en delmengde av en annen mengde. Last ned filen her: :download:`eksempel_7.py`, og kjør koden. Skjønner du hva som skjer? .. literalinclude:: eksempel_7.py .. _uke_09_oppgave_7: Oppgave 7 ......... I filen ``uke_09_oppg_7.py`` skriv en funksjon som heter ``word_comparison()`` og som tar to ord (strenger) som argumenter. Funksjonen skal så sammenligne bokstavene i ordene og returnere en dictionary som sier hvilke bokstaver finnes i begge ordene, hvilke bokstaver som finnes i kun det første ordet og hvilke bokstaver som finnes i kun det andre ordet (som ``set``). For eksempel skal ``word_comparison("computer","science")`` returnere følgende dictionary (husk at orden i mengder ikke spiller noen rolle): .. code-block:: python { "In common": {"e", "c"}, "Unique to first word": {"r", "u", "t", "p", "o", "m"}, "Unique to second word": {"s", "i", "n"}, } Oppgaver -------- Oppgave 1 ......... Du finner :ref:`uke_09_oppgave_1` nedenfor Eksempel 1. Oppgave 2 ......... Du finner :ref:`uke_09_oppgave_2` nedenfor Eksempel 1. Oppgave 3 ......... Du finner :ref:`uke_09_oppgave_3` nedenfor Eksempel 2. Oppgave 4 ......... Du finner :ref:`uke_09_oppgave_4` nedenfor Eksempel 3. Oppgave 5 ......... Du finner :ref:`uke_09_oppgave_5` nedenfor Eksempel 4. Oppgave 6 ......... Du finner :ref:`uke_09_oppgave_6` nedenfor Eksempel 5. Oppgave 7 ......... Du finner :ref:`uke_09_oppgave_7` nedenfor Eksempel 7. Oppgave 8 ......... `Fantasy Game Inventory` fra boken (https://automatetheboringstuff.com/2e/chapter5/) Du lager et fantasy-videospill. Datastrukturen for å modellere spillerens beholdning skal være en dictionary hvor nøklene er strings som beskriver tingene i beholdningen, og verdiene er integers som forteller hvor mange av hver ting som spilleren har. For eksempel, verdiene i dictionary ``{'rope': 1, 'torch': 6, 'gold coin': 42, 'dagger': 1, 'arrow': 12}`` betyr at spilleren har 1 rope, 6 torches, 42 gold coins, etc. Last ned filen :download:`uke_09_oppg_8_start.py ` og skriv resten av funksjonen ``displayInventory()`` som tar inn en dictionary av beholdningen og returneres totalt antall i formaten i eksempelkjøringen nedenfor. Eksempelkjøring: .. code-block:: python >>> stuff = {"rope": 1, "torch": 6, "gold coin": 42, "dagger": 1, "arrow": 12} >>> displayInventory(stuff) Inventory: 1 rope 6 torch 42 gold coin 1 dagger 12 arrow 62 Funksjonen skal i dette eksemplet returnere tallet :math:`62` (den siste linjen). Oppgave 9 ......... `Dragon Hoard` fra boken (https://automatetheboringstuff.com/2e/chapter5/) Skatten til en beseiret drage er representert som en liste med strenger som dette: ``dragonLoot = ['gold coin', 'dagger', 'gold coin', 'gold coin', 'ruby']`` Fyll inn funksjonen som heter ``addToInventory(inventory, addedItems)``, hvor ``inventory`` parameteren er en dictionarien av spillerens beholdning og ``addedItems`` parameteren er en liste som f.eks ``dragonLoot``. ``addToInventory()`` funksjonen skal returnere en dictionary som representerer den oppdaterte beholdningen. Merk at listen over tilleggsartikler kan inneholde flere av samme element. Last ned filen :download:`uke_09_oppg_9_start.py ` og skriv resten av funksjonen som heter ``addToInventory()``. Om du kaller ``displayInventory()`` etter å ha oppdatert beholdingen med ``addToInventory()`` funksjonen skal du få ut likt som nedenfor: .. code-block:: python >>> inv = {"gold coin": 42, "rope": 1} >>> dragonLoot = ["gold coin", "dagger", "gold coin", "gold coin", "ruby"] >>> inv = addToInventory(inv, dragonLoot) >>> displayInventory(inv) Inventory: 45 gold coin 1 rope 1 dagger 1 ruby 48 og ``displayInventory()`` skal returnere tallet :math:`48`. Oppgave 10 - Euler 17 ..................... Følgende tekst er herifra: https://projecteuler.net/problem=17 If the numbers 1 to 5 are written out in words: one, two, three, four, five, then there are 3 + 3 + 5 + 4 + 4 = 19 letters used in total. If all the numbers from 1 to 1000 (one thousand) inclusive were written out in words, how many letters would be used? NOTE: Do not count spaces or hyphens. For example, 342 (three hundred and forty-two) contains 23 letters and 115 (one hundred and fifteen) contains 20 letters. The use of "and" when writing out numbers is in compliance with British usage. I filen ``uke_09_oppg_10.py`` skal du gjøre følgende: **Skriv en funksjon number_name(N)** som tar inn et heltall (opp til 1000) som argument ``N`` og returnerer det engelske navnet til tallet som en streng. *Tips:* begynn med dict'et som finnes i Eksempel 4, og legg inn flere tall der. Du trenger ikke å ta med alle tallene frem til 1000, siden de fleste kan settes sammen. Gjerne bruk flere funksjoner for å organisere programmet ditt. **Skriv en funksjon all_numbernames(N)** som tar inn et heltall (opp til 1000) som argument N og returnerer den summerte lengden av alle navnene fra 1 til N (sjekk eksemplene fra Euler-teksten). Du kan gjenbruke ``number_name()`` her. **Skriv en funksjon solve_euler_17()** som returnerer den summerte lengden av alle navnene fra 1 til 1000. Du kan gjenbruke de andre funksjonene.