Uke 9 - Dict / Files ==================== 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" Vi skal også lese data fra en fil for første gang her. Se på Section 7.2 og 7.2.1 i Python Tutorial: https://docs.python.org/3/tutorial/inputoutput.html#reading-and-writing-files 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 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 Eksempel 3 .......... Vi kan bruke alle 'immutable data types' som keys i en dictionary. For eksempel kan vi bruke heltall. Last ned filen her: :download:`eksempel_3.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_3.py Eksempel 4 .......... 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'. Du finner informasjon om modulen ``string`` `i Pythons dokumentasjon `_. Last ned filen her: :download:`eksempel_4.py`, og kjør koden. Skjønner du hva som skjer? Hva gjør ``.setdefault()``? (Du kan lese om den `i Pythons dokumentasjon `_.) 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 `_. .. literalinclude:: eksempel_4.py Eksempel 5 .......... I dette eksemplet skal vi prøve å lese og skrive til en fil. Du må laste ned denne tekstfilen: :download:`timemachine.txt` Last ned filen her: :download:`eksempel_5.py`, og kjør koden. Hva er forskjellen mellom ``for line in f``, ``f.readlines()`` og ``f.read()`` for å lese fra filen? Hva skjer når du åpner filen 'numbers.txt' med mode 'w' i slutten? .. literalinclude:: eksempel_5.py Eksempel 6 .......... I dette eksempelet teller vi hvor mange ganger ulike bokstaver og ord blir brukt i hele boken 'Alice in wonderland'. Derfor vil vi lese in teksten fra en fil, istedet for å lime hele teksten inn i filen med python-kode. Til dette eksemplet må du laste ned denne tekstfilen: :download:`alice.txt`. Koden er i denne filen: :download:`eksempel_6.py`. Kjør koden. Skjønner du hva som skjer? .. literalinclude:: eksempel_6.py Oppgaver -------- ..note:: Gå gjennom denne ukens innhold før du begynner! **Du får din kopi av oppgavene på git.app.uib.no. Oppgavene skal leveres ved push til det repoet innenfor 2020-10-23 23:59. Du kan pushe så mange ganger du vil før fristen og du får automatisk tilbakemelding hver gang.** Del 1 - Euler 17 ---------------- 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. **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 3) **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) **Skriv en funksjon solve_euler_17()** som returnerer den summerte lengden av alle navnene fra 1 til 1000 Del 2 - Filnavn (basert på eksamen 20V) --------------------------------------- I løpet av forskningsprosjektet ditt har du samlet inn mange datafiler. Alle filer har .txt format, og de første linjene i hver fil inneholder sted og tidspunkt hvor og når data ble samlet inn. Akkurat nå har filene tilfeldige navn (qwghlm, qwerty, ...), som gjør det vanskelig å finne et datasett uten å åpne alle filene. Du vil gjerne gi bedre navn til filene, basert på informasjonen som finnes i hver fil. For eksempel, en fil som heter "qwghlm.txt" starter med:: Tromso 2020-05-07 3.141 2.7172 4.567 1.234 2.7172 4.567 1.234 9.8165 [... mange flere data-linjer ...] og filen "qwerty.txt" starter med:: Oslo 2019-06-01 -5.141 8.7272 -4.567 1.2364 12.7172 44.5367 1.234 9.81372 [...] **Skriv en funksjon rename_from_data(filename)** som * tar inn et filnavn som argument, * leser inn filen som er nevnt, * tar sted og dato fra de første to linjene * lager et nytt filnavn fra dato og sted, med .txt til slutt. Formatet skal være ``YYYY-MM-DD_PLACENAME.txt`` * lagrer all data fra den opprinnelige filen (uten sted og tid) inn i en ny fil med det nye filnavnet **Skriv en funksjon rename_all(namelist)** som tar inn en liste med filnavn og bruker rename_from_data() på hver fil i listen. I eksempelet vårt inneholder namelist listen ["qwghlm.txt","qwerty.txt"]. Funksjonen din skal gå gjennom listen og lagre en ny fil for hver gammel fil. Innholdet av "qwghlm.txt" skal lagres som "2020-05-07_Tromso.txt" og innholdet av "qwerty.txt" skal lagres som "2019-06-01_Oslo.txt". Det finnes ingen testfiler i mappen, men du kan lage dem selv om du trenger det. Del 3 - Havnivå 1 ----------------- *Du skal ikke bruke ``import`` her, men du kan legge til flere hjelpefunksjoner* I filen ``VIK_sealevel_2000.txt`` finnes målinger av havnivået på et sted, hvor en linje i filen representerer én måling, repetert for hver time i året 2000. Det finnes 8784 linjene i alt, og formatet er :: year month day hour height[cm] **Skriv en funksjon read_file(filename)** som tar et filnavn av en slik datafil som argument og returnerer en liste av tuples med 5 heltall. I vårt eksempelfil begynner og slutter listen slik:: [ (2000, 1, 1, 1, 335), (2000, 1, 1, 2, 336), (2000, 1, 1, 3, 338), # ... (2000, 12, 31, 22, 337), (2000, 12, 31, 23, 338), (2000, 12, 31, 24, 339) ] Alle følgende funksjonene tar inn denne listen som argument. **Skriv en funksjon average(data, month=None)** som tar inn datalisten og et argument ``month`` med standardverdi ``None``. Hvis ``month`` er ``None``, skal funksjonen returnere gjennomsnittet av alle målingene. Hvis ``month`` er gitt som et tall 1-12, skal funksjonen returnere gjennomsnittet av alle målingene i den tilsvarende måneden. **Skriv en funksjon add_weekday(data)** som tar inn datalisten og returnerer an ny dataliste med 6 kolonner. Den 6. kolonnen skal inneholde ukedag som en streng (``Sat Sun Mon Tue Wed Thu Fri``). 2000-01-01 var en lørdag (``Sat``), 2000-12-31 var en søndag (``Sun``). For eksempeldatasettet ser returnverdien slik ut:: [ (2000, 1, 1, 1, 335, 'Sat'), (2000, 1, 1, 2, 336, 'Sat'), (2000, 1, 1, 3, 338, 'Sat'), # ... (2000, 12, 31, 22, 337, 'Sun'), (2000, 12, 31, 23, 338, 'Sun'), (2000, 12, 31, 24, 339, 'Sun') ] **Skriv en funksjon average_weekday(data, weekday)** som tar inn den utvidete datalisten og et argument ``weekday`` som er en av strengene ``Sat Sun Mon Tue Wed Thu Fri``. Funksjonen skal returnere gjennomsnittet av alle målingene for tilsvarende ukedagen. Del 4 - Havnivå 2 ----------------- *Du skal ikke bruke ``import`` her, men du kan legge til flere hjelpefunksjoner** **Skriv en funksjon max_indexes(xs)** som tar inn en liste ``xs`` med tall, og returnerer en liste av indeksposisjoner hvor listen har lokale maksimalverdier. Et lokalt maksimum er et tall i listen som har mindre tall før og etter. F.eks har denne listen et lokalt maksimum på posisjon 2 og 7:: [3, 4, 5, 2, 1, 0, 4, 6, 4, 2, 1] . *** *** Funksjonen skal returnere ``[2, 7]`` her. Om flere verdier er like, returnerer vi den siste indexposisjonen: Input ``[2,3,3,1]`` har output ``[2]``. Bruk denne funksjonen sammen med ``read_file(filename)`` funksjonen og datasett fra del 3 for å finne ut gjennomsnittsavstand mellom to høyvann-episoder. Du kan strukturere koden fritt, slik som du trenger.