Uke 7 — list / tuple / string ================================ Denne uken avslutter vi med lister og tupler. Les https://automatetheboringstuff.com/2e/chapter4/ frem til "A Short Program: Conway’s Game of Life." Eksempler --------- Eksempel 1: Tupler .................. Tupler er litt som en liste, men bruker ``()`` isteden for ``[]``. Vi bruker vanligvis tupler for objekter hvor lengden ikke vil endres, dvs. antall objekter/elementer forventes å være statiske. Det er noen viktige forskjeller på tupler og lister som vi skal se på seinere. I dette eksempelet lager vi noen tupler og ser hvordan de kan brukes. Last ned filen her: :download:`eksempel_1_tuple.py`, og kjør koden. .. literalinclude:: eksempel_1_tuple.py .. _uke_07_oppgave_1: Oppgave 1 ......... I ``uke_07_oppg_1.py`` skal du skrive en funksjon som bytter ut favorittleken til en hund. Lag en funksjon kalt ``swap_tuple()`` som tar som argument en tuple med **tre** strenger. Den første strengen er hundens navn. Den andre strengen er hundens personlighet. Den tredje strengen er favoritleken til hunden. Du skal bytte ut favoritleken til ``"ball"``. Eksempelkjøring: .. code-block:: python >>> dog = ("Ollie", "joy", "squeaky toy") >>> print(swap_tuple(dog)) ("Ollie", "joy", "ball") Eksempel 2: Sekvenser ..................... Her er noen eksempler på lister, tupler og strenger. Alle tre kan indekseres på den samme måten, og alle tre kan brukes i for-løkker. Vi kan også konvertere mellom disse tre sekvensene. Last ned filen her: :download:`eksempel_2_sequence_types.py`, og kjør koden. Skjønner du hva som skjer? .. literalinclude:: eksempel_2_sequence_types.py .. _uke_07_oppgave_2: Oppgave 2 ......... I denne oppgaven får vi data om ukens maks temperaturer som én ``str``. For eksempel kan dataen se slik ut: .. code-block:: python "6.0 9.0 10.0 10.0 12.0 10.0 11.0" # Mandag - Søndag I ``uke_07_oppg_2.py``, skriv en funksjon som heter ``update_weather()`` og som tar en slik streng med én ukes temperaturer og lager en tuple med temperaturene konvertert til ``float`` (i samme orden). Eksempelkjøring: .. code-block:: python >>> update_weather("6.0 9.0 10.0 10.0 12.0 10.0 11.0") (6.0, 9.0, 10.0, 10.0, 12.0, 10.0, 11.0) I ``uke_07_oppg_2.py`` skriv også en funksjon som heter ``wednesday_weather()`` og som tar en tuple med en ukes temperaturer som ``float`` og returnerer temperaturen på onsdag (også som en ``float``). Eksempelkjøring: .. code-block:: python >>> wednesday_weather(6.0, 9.0, 10.0, 10.0, 12.0, 10.0, 11.0) 10.0 Eksempel 3a: Foranderlig / ikke foranderlig ........................................... Lister, tupler og strenger er like på mange måter, hovedforskjellen er at listene **kan** endres, vi kaller det for "mutable". Her er noen eksempler på forskjellen mellom lister (som kan forandres), og tupler, som er 'immutable' (som **ikke kan** forandres). Last ned filen her: :download:`eksempel_3a_mutable.py`, og kjør koden. Skjønner du hva som skjer? Hvorfor blir ``b`` endret etter ``a += [999, 777]``? Hvorfor blir ``b`` ikke endret etter ``a += (999, 777)``? .. literalinclude:: eksempel_3a_mutable.py Eksempel 3b: Referanser ....................... Nå skal vi bruke `visualiseringsverktøyet på pythontutor.com `_ for å se hvordan referanser fungerer i python med et konkret ekesempel. Åpne lenken ovenfor og klikk "Next" for å gå trinnvis gjennom koden. Følg nøye med på hva som skjer på hvert trinn. Hvordan er ``m`` relatert til ``a``? Hvordan forholder ``b`` seg til ``m``? Hvordan forholder ``c`` seg til ``m``? Hvilke listene er det som får *appended* den ekstra listen i linje 9? (Du kan også laste ned filen her: :download:`eksempel_3b_ref.py`, og kjøre koden på datamaskinen din uten visualiseringen.) .. literalinclude:: eksempel_3b_ref.py I dette eksempelet kan vi se at ``m`` er en liste av lister og at ``a`` er den samme listen av lister. Variabelen ``b`` er en kopi av listen ``m``, som har *referanser* til de andre listene i listen ``m``. Derimot så er ``c`` helt annerledes fra de andre: det er en ny liste, med en ny versjon av listene i listen med de samme verdiene. Listene i ``c`` referer *ikke* til de samme listene som i ``m``. .. _uke_07_oppgave_3: Oppgave 3 ......... La oss nå prøve en oppgave som viser mutabilitet og referanser, som ligner på dette eksemplet. Som før, om du blir sittende fast, kan du lese gjennom dette eksemplet ovenfor igjen for å få litt hjelp. Du har et dataset som inneholder de forutsagte makstemperaturene fra mandag til lørdag denne uken (se nedenfor). Men du fant ut at den forutsagte temperaturen på torsdagen ikke var riktig. Makstemperaturen skal bli 12.0. Du vil gjerne korrigere den, men vil heller gjøre det med en kopi av originalen som lar originalen være uendret. I oppgaven ``uke_07_oppg_3.py`` skriv en funksjon som heter ``adjust_daily_temps()`` og som endrer fredagens temperatur til ``10.0``, og returnerer det oppdaterte resultatet. Resultatet må være en **tuple** som originallisten. Eksempelkjøring: .. code-block:: python >>> daily_temps = (('mandag', 6.0), ('tirsdag', 9.0), ('onsdag', 10.0), ('torsdag', 10.0), ('fredag', 12.0), ('lørdag', 10.0), ('søndag', 11.0)) >>> adjust_daily_temps(daily_temps) (('mandag', 6.0), ('tirsdag', 9.0), ('onsdag', 10.0), ('torsdag', 10.0), ('fredag', 10.0), ('lørdag', 10.0), ('søndag', 11.0)) Eksempel 4a: zip() ................. ``zip()`` er en innebygd funksjon som "zipper" sammen sekvensene som blir gitt inn og returnerer en liste av tupler. En sekvens kan f.eks. være en liste, streng eller en tuple. ``zip`` tar det første elementet fra hver sekvens og legger de sammen i en tuple, og så det andre elementet i hver sekvens og legger de sammen osv. Om sekvensene har ulik lengde, er det den korteste sekvensen som bestemmer lengden til ``zip()`` -outputet. Last ned filen her: :download:`eksempel_4_zip.py`, og kjør koden. .. literalinclude:: eksempel_4_zip.py Eksempel 4b: Turtle ................... Vi kan demonstrere bruken av ``zip()`` med ``turtle`` eksemplet fra uke_06 med de to listene ``angles`` og ``lengths`` hvor ``zip()`` er lett å bruke for å combinere disse to listene til én 2D list i format ``[(angle1, length1),(angle2, length2), ...]``. Vi kontrast denne metoden med en standard for loop-metode i koden nedenfor. Last ned filen her: :download:`eksempel_4_turtle.py`, og kjør koden. .. literalinclude:: eksempel_4_turtle.py .. _uke_07_oppgave_4a: Oppgave 4a .......... I denne oppgaven får vi gitt to tupler med navn, personlighet og favorittlek til to hunder. I filen ``uke_07_oppg_4a.py``, skriv en funksjon som heter ``tuple_repack()`` og tar to tupler med hundinformasjon og returnerer en liste med hudenes personligheter (i samme orden). Eksempelkjøring: .. code-block:: python >>> tuple_repack(("Ollie","joy","ball"), ("Iggy","nervous","squeaky toy")) ["joy", "nervous"] .. note:: **TIPPS:** Du kan bruke ``zip()`` og få ut resultatet derfra. .. _uke_07_oppgave_4b: Oppgave 4b .......... I denne oppgaven blir vi igjen gitt en tuple med forutsagte temperaturer i en uke. I filen ``uke_07_oppg_4b.py``, skriv en funksjon som heter ``data_reorganize()`` og som zipper tuplen dataen til en ny tuple som inneholder dagene som en tuple og temperaturene some en annen tuple. Funksjonen skal den resulterende omorganiserte tuplen. Eksempelkjøring: .. code-block:: python >>> days_paired_temperatures = (("mandag", 10.0),("tirsdag", 9.0),("onsdag", 10.0),("torsdag", 9.5),("fredag", 11.5),("lørdag", 8.5),("søndag", 11.0)) >>> data_reorganize(days_paired_temperatures) (('mandag', 'tirsdag', 'onsdag', 'torsdag', 'fredag', 'lørdag', 'søndag'), (10.0, 9.0, 10.0, 9.5, 11.5, 8.5, 11.0)) Eksempel 5: enumerate() ........................ Den innebygde funksjonen ``enumerate()`` er et alternativ til å bruke ``range(len(myList))`` med en for-løkke for å få indeksen til elementene i listen. På hver iterasjon av løkken vil ``enumerate()`` returnere to verdier: (1) indeksen til elementet i listen og (2) selve elementet i listen. Last ned filen her: :download:`eksempel_5_enum.py`, og kjør koden. Hva er forskjellen mellom disse to? Hvilken er lettere for deg å forstå? .. literalinclude:: eksempel_5_enum.py .. _uke_07_oppgave_5: Oppgave 5 ......... Du har en database med målinger hentet fra en sonde som måler vindhastighet. Sonden registrerer vindhastighet hver time. Hver 12. time kalibreres sonden. I ``uke_07_oppg_5.py`` skriv en funksjon som heter ``calibration_readout()`` og som tar en liste med ``float`` som argument (vindhastighetene). Anta at den første verdien i listen er målet i løpet av en kalibreringstime. Funksjonen skal bruke ``enumerate()`` for å returnere listen med vindhastigheter men hvor alle verdiene som er fra kalibreringstimer er byttet ut til en tuple med første verdien ``"Calibration hour"`` og andre verdien vindhastigheten. For eksempel, om ``calibration_readout()`` brukes på følgende liste: .. code-block:: python >>> wind_speed = [3.0, 4.0, 3.5, 5.5, 1.0, 0.3, 3.0, 4.5, 6.0, 11.0, 12.0, 1.0, 2.0, 2.0] [('Calibration hour', 3.0), 4.0, 3.5, 5.5, 1.0, 0.3, 3.0, 4.5, 6.0, 11.0, 12.0, 1.0, ('Calibration hour', 2.0), 2.0] Eksempel 6: Finne feilene ......................... Her er noen eksempler på ting som kan gå feil. Last ned filen her: :download:`errors_1.py`. Før du kjør koden, se om du finner alle feil som gjør at den ikke går å kjøre. Kjør siden koden. Fant du alle feil? Endre koden så at den går å kjøre. Koderaden ``greeting_str = str(full_greeting)`` er ikke feil slik at man får en error fra Python, men den gjør ikke akkurat hva vi vil at den skal gjøre. Endre så at det blir riktig output. .. literalinclude:: errors_1.py :linenos: Oppgaver -------- Oppgave 1 ......... Se :ref:`uke_07_oppgave_1` rett nedenfor ekesempelen *tupler*. Oppgave 2 ......... Se :ref:`uke_07_oppgave_2` rett nedenfor ekesempelen *sekvenser*. Oppgave 3 ......... Se :ref:`uke_07_oppgave_3` rett nedenfor ekesempelen *forandres vs ikke forandres*. Oppgave 4a .......... Se :ref:`uke_07_oppgave_4a` rett nedenfor ekesempelen ``zip()``. Oppgave 4b .......... Se :ref:`uke_07_oppgave_4b` rett nedenfor ekesempelen ``zip()``. Oppgave 5 ......... Se :ref:`uke_07_oppgave_5` rett nedenfor ekesempelen ``enumerate()`` Oppgave 6 ......... I filen ``uke_07_oppg_6.py``, skriv en funksjon som heter ``pigify()`` og som oversetter et ord fra engelsk til pig latin. Oversettelsen gjøres på følgende måte: 1. Hvis et ord begynner med en vokal, skal funksjonen legge til **-way** på slutten av ordet (e.g., apple ↦ appleway). (I denne oppgaven regner vi **ikke** y som en vokal.) 2. Hvis ordet begynner med en konsonant, skal funksjonen flytte alle bokstavene i begynnelsen av ordet frem til den første vokalen, til slutten av ordet, og legge til **-ay** etter det (e.g., banana ↦ ananabay, string ↦ ingstray). (Hvis ordet bare inneholder konsonanter så skal kun **-ay** legges til på slutten av ordet.) Eksemplkjøring: .. code-block:: python >>> pigify("door") "oorday" Skriv også en funksjon som heter ``pigify_sentence()`` som tar en setning som argument (som en ``string``) og som returnerer tilsvarende setning men ver hvert ord er oversatt til pig latin. Du kan anta at alle setinger funksjonen blir kalt med ikke inneholder spesialtegn eller store bokstaver. Eksempelkjøring: .. code-block:: python >>> pigify_sentence("time will not slow down when something unpleasant lies ahead" "imetay illway otnay owslay ownday enwhay omethingsay unpleasantway ieslay aheadway" Oppgave 7 .......... *Tilpasset fra The Python Workbook, Ex. 117:* En linje med best tilpasning er en rett linje som best tilnærmer en samling av :math:`{n}` datapunkter. Variablene :math:`\bar{x}` og :math:`\bar{y}` brukes å representere gjennomsnittsverdiene i samlingen. Linjen med best tilpasning er representert ved ligningen :math:`y = mx + b` hvor :math:`{m}` og :math:`{b}` beregnes ved hjelp av følgende formler: .. math:: m = \frac{ \sum{xy} - \frac{( \sum{x})( \sum{y})}{n}}{ \sum{x^2} - \frac{( \sum{x})^2}{n}} .. math:: b = \bar{y} - m \bar{x} I filen ``uke_07_oppg_7.py`` skal du lage en funksjon med navnet ``line_best_fit()`` som tar som argument en tuple av koordinater i tuple form ``((x1, y1), (x2, y2), ...)``. Funksjonen skal returnere formelen for linjen med best tilpasning i formen :math:`y = mx + b`, hvor variablene :math:`{m}` og :math:`{b}` erstattes med verdiene du beregnet for formlene ovenfor for :math:`{m}` og :math:`{b}`. Om verdien til :math:`{b}` er ``0``, må formlene **ikke** inkludere :math:`{b}`. Eksempelkjøring: .. code-block:: python >>> coord_1 = ((1, 1), (2, 2.1), (3, 2.9)) >>> line_best_fit(coord_1) y = 0.95x + 0.1 >>> coord_2 = ((0, 0), (1, 1), (2, 2), (3, 3)) >>> line_best_fit(coord_2) y = 1.0x .. note:: **TIPPS**: Du kan bruke ``zip()`` for noen av beregningene for x og y for å løse for m og b, eller du kan bruke for-løkker. Før du begynner å prøve å kode, sørg for at du vet hva du trenger å beregne, og del problemet i mindre biter basert på hver av disse mindre verdiberegningene du må gjøre.