Lab7
Innlevering på CodeGrade og autotester er dessverre litt forsinket. Vi jobber med saken.
Grunnleggende oppgaver (E):
Nivå A-D:
Viktig: studer og forstå godt kursnotatene om filer og CSV. I tillegg er det lurt å skumme gjennom kursnotatene om å håndtere krasj med try/except.
Sum med strenger
I filen string_sum.py skal du skrive en enkel funksjon kalt add_together(s)
. Anta at parameteren s
er en streng hvor noen av «ordene» representerer tall (ulike ord i strengen er skilt av mellomrom). Funksjonen skal returnere summen av de ordene i strengen som er heltall. Hvis ingen av strengene inneholder heltall, skal funksjonen returnere 0
.
Test koden din ved å legge til disse linjene nederst i filen:
print('Tester add_together... ', end='')
assert 6 == add_together('4 2')
assert 9 == add_together('5 -1 3 2')
assert 0 == add_together('foo bar qux')
assert 42 == add_together('foo 42 qux')
assert 42 == add_together('foo2 42 2qux 3x1')
assert 0 == add_together('-9- 3-2')
print('OK')
Split-metoden klipper opp en streng ved et gitt symbol, og returnerer en liste av bitene som er igjen.
# Eksempler på bruk av .split()
s = 'foo bar qux'
parts = s.split(' ') # parts er nå en liste ['foo', 'bar', 'qux']
print(parts[1]) # bar
s = '3;9;42'
parts = s.split(';') # parts er nå en liste ['3', '9', '42']
print(parts[0] + parts[2]) # 342
- Begynn med å benytte
.split()
-metoden for å omgjøre strengen til en liste av ord. - Bruk en løkke for å gå igjennom alle elementene i listen.
- Før løkken starter, opprett en variabel som holder den løpende totalsummen initiert med verdien
0
. For hver iterasjon av løkken kan det være vi legger til et nytt tall til denne variabelen. - Benytt try-except når du forsøker å konvertere strengen til heltall. Dersom omgjøringen feiler, hopp over dette elementet og fortsett videre med neste element i listen.
- Returner totalsummen når løkken er ferdig.
Høye temperaturer
I high_temperatures.py, skriv en funksjon som heter filter_high_temperatures med parametre:
path_input
, en filsti til en eksisterende fil som inneholder temperaturdata for hver måned. Hver linje består av månedens navn etterfulgt av minimums- og maksimumstemperaturen, adskilt med mellomrom. For eksempel, temperatures.txt.path_output
, en filsti til en fil som skal opprettes, ogthreshold_temp
, et flyttall som representerer en temperatur.
La funksjonen åpne filen path_input
, gå gjennom linjene i filen og lage en ny fil path_output
hvor kun de linjene der maksimumstemperaturen er minst threshold_temp
er inkludert. Om ingen måneder har en maksimum temperatur som er minst threshold_temp
så skal path_output
være en tom fil.
Test koden din ved å laste ned temperatures.txt og legg til disse linjene nederst i filen:
print('Tester filter_high_temperatures... ', end='')
filter_high_temperatures('temperatures.txt', 'max_temps.txt', 15)
expected_result = '''\
Mars 3 20
April 6 20
Mai 9 25
Juni 12 30
Juli 15 28
August 15 20
September 12 15
'''
with open('max_temps.txt', 'rt', encoding='utf-8') as f:
actual_result = f.read()
assert expected_result.strip() == actual_result.strip()
print('OK')
- Les innholdet i filen
path_input
og lagre det i en variabel. - Opprett en liste for linjene vi senere skal skrive til filen
path_output
. Initier den som en tom liste. - Gå gjennom hver linje i innholdet (se f. eks. splitlines-metoden).
- For hver linje: benytt split -metoden for å dele opp linjen i tre deler: månedens navn, minimumstemperaturen og maksimumstemperaturen.
- Omgjør maksimumstemperaturen til et flyttall og sammenlign med
threshold
. Hvis temperaturen er tilstrekkelig høy, legg til linjen i listen vi opprettet tidligere.
- Åpne filen
path_output
i skrivemodus. Skriv ut linjene i listen til filen. Husk linjeskift.
Kraftige jordskjelv
Denne oppgaven består av tre deler. Skriv funksjoner til alle deloppgaver i én felles fil, high_impact.py.
Eksempelet under er en forkortet og forenklet oversikt over registrerte jordskjelv i CSV format hentet fra CORGIS.
id;location;impact;time
nc72666881;California;1.43;2016-07-27 00:19:43
us20006i0y;Burma;4.9;2016-07-27 00:20:28
nc72666891;California;0.06;2016-07-27 00:31:37
I dennne oppgaven skal vi skrive et program som leser inn en CSV-fil med formatet over, og produserer en ny fil som inneholder alle de rekkene i den første filen hvor impact er større enn en gitt verdi.
Det finnes biblioteker som gjør håndtering av CSV-filer enklere, og det skal vi se mer på senere i kurset. I denne oppgaven skal vi derimot ikke importere biblioteker for CSV-håndtering, men kun bruke standard streng-metoder og kode vi har skrevet selv.
Del A
Skriv en funksjon get_impact(line)
som får én enkelt linje (en streng) som input, og som returnerer impact-kolonnen i den linjen som et flyttall. Dersom det er noe feil med input som gjør at det ikke er mulig å se hvilken styrke jordskjelvet har, skal funksjonen returnere None
, men ikke krasje.
Test koden din ved å legge til disse linjene nederst i filen:
print("Tester get_impact... ", end="")
assert 1.43 == get_impact("nc72666881;California;1.43;2016-07-27 00:19:43")
assert 4.9 == get_impact("us20006i0y;Burma;4.9;2016-07-27 00:20:28")
assert None is get_impact("us20006i0y;Burma;not_a_number;2016-07-27 00:20:28")
print("OK")
Del B
Skriv en funksjon filter_earthquakes(earthquake_csv_string, threshold)
som tar inn en streng earthquake_csv_string
med CSV-data på formatet vist over, samt et flyttall threshold
. Funksjonen skal returnere en streng på samme format, men hvor linjer med impact strengt lavere enn threshold
-verdien og linjer hvor det ikke er gyldig impact-verdi ikke er inkludert.
Test koden din ved å legge til følgende linjer nederst i filen:
print("Tester filter_earthquakes... ", end="")
input_string = """\
id;location;impact;time
nc72666881;California;1.43;2016-07-27 00:19:43
us20006i0y;Burma;4.9;2016-07-27 00:20:28
nc72666891;California;0.06;2016-07-27 00:31:37
nc72666892;California;not_a_number;2016-08-23 03:21:18
"""
# Test 1
expected_value = """\
id;location;impact;time
nc72666881;California;1.43;2016-07-27 00:19:43
us20006i0y;Burma;4.9;2016-07-27 00:20:28
"""
actual_value = filter_earthquakes(input_string, 1.1)
assert expected_value.strip() == actual_value.strip()
# Test 2
expected_value = """\
id;location;impact;time
us20006i0y;Burma;4.9;2016-07-27 00:20:28
"""
actual_value = filter_earthquakes(input_string, 3.0)
assert expected_value.strip() == actual_value.strip()
# Test 3
expected_value = """\
id;location;impact;time
"""
actual_value = filter_earthquakes(input_string, 5.0)
assert expected_value.strip() == actual_value.strip()
print("OK")
- Benytt en for-løkke og .splitlines -metoden for å gå igjennom alle linjene med data. Husk at den første linjen må behandles annerledes
- Bruk funksjonene fra forrige deloppgave for å finne ut om en gitt linje skal legges til i resultatet eller ikke.
- Husk å legge til linjeskift.
Del C
Skriv en funksjon filter_earthquakes_file(source_filename, target_filename, threshold)
som tar inn navnet på to filer, samt en grenseverdi. Funksjonen skal gjøre det samme som i forrige deloppgave, men leser inn data fra source_filename
, og skriver ut data til target_filename
.
For å teste funksjonen, last ned earthquakes_simple.csv og legg den i mappen hvor du kjører programmet fra. Legg deretter til koden under nederst i filen:
print('Tester filter_earthquakes_file... ', end='')
def read_file(path):
with open(path, 'rt', encoding='utf-8') as f:
return f.read()
filter_earthquakes_file('earthquakes_simple.csv',
'earthquakes_above_7.csv', 7.0)
expected_value = '''\
id;location;impact;time
us100068jg;Northern Mariana Islands;7.7;2016-07-29 17:18:26
us10006d5h;New Caledonia;7.2;2016-08-11 21:26:35
us10006exl;South Georgia Island region;7.4;2016-08-19 03:32:22
'''
actual_value = read_file('earthquakes_above_7.csv')
assert expected_value.strip() == actual_value.strip()
print('OK')
# Manuell test: Finn earthquakes_above_7.csv, åpne og se at innholdet stemmer
Første bokstav siste ord
Denne oppgaven består av to deler. Skriv funksjonen i filen first_of_last.py.
Del A
Skriv en funksjon som heter first_letter_last_word(filepath)
som åpner en fil med den gitte filstien, og returnerer en streng som består av den første bokstaven til det siste ordet i hver linje. Tomme linjer ignoreres. Kjør programmet ditt på filen askeladden.txt.
Test koden din ved å legge til disse linjene nederst i filen:
print('Tester first_letter_last_word... ', end='')
assert('sti' == first_letter_last_word('askeladden.txt'))
# Forklaring:
# Siste ord i første linje er 'sønner.' Første bokstav i dette ordet er 's'
# Siste ord i andre linje er 'til.' Første bokstav i dette ordet er 't'
# Siste ord i tredje linje er 'i.' Første bokstav i dette ordet er 'i'
print('OK')
Del B
Her gjør vi det samme som i forrige del oppgave, men funksjonen skal ikke krasje hvis vi nevner en fil som ikke finnes, dvs når en FileNotFoundError oppstår.
Skriv en funksjon som heter first_letters(filepath)
som bruker first_letter_last_word(filepath)
fra Del A. Funksjonen skal ta et filsti som argument og returnere en streng med den første bokstaven i det siste ordet for hver linja av filen. Hvis filen ikke finnes skal den returnere en tom streng ''
.
Test koden din ved å legge til disse linjene nederst i filen:
print('Tester first_letters... ', end='')
assert('sti' == first_letters('askeladden.txt'))
assert('' == first_letters('de_tre_bukkene_bruse.txt'))
print('OK')
God stil
Denne oppgaven består av to deler. Skriv funksjoner til begge deloppgaver (A og B) i én felles fil, nice_style.py.
Del A
Tradisjonelt regnes 80 tegn for å være den maksimale lengden på en linje for å ha en god kodestil. Selv om moderne skjermer er i stand til å vise flere tegn på en linje, regnes grensen på 80 fremdeles for å være en god tommelfingerregel, og er for eksempel en del av Python sin offisielle stil-guide PEP 8.
Skriv funksjonen good_style(source_code)
som returnerer True
hvis alle linjene i strengen source_code
er mindre enn eller lik 80 tegn, False
ellers.
Merk at grensen på 80 tegn inkluderer selve linjeskift-symbolet på slutten av linjen, slik at det i praksis blir maksimalt 79 tegn på hver linje.
Test koden din ved å legge til disse linjene nederst i filen:
print("Tester good_style... ", end="")
assert(good_style("""\
def distance(x0, y0, x1, y1):
return ((x0 - x1)**2 + (y0 - y1)**2)**0.5
"""))
assert(good_style((("x" * 79) + "\n") * 20))
assert(not good_style("x" * 80))
assert(not good_style((("x" * 79) + "\n") * 5 +
(("x" * 80) + "\n") +
(("x" * 79) + "\n") * 5))
print("OK")
Benytt en løkke som itererer over alle linjene i en streng. string.splitlines()
kan hjelpe her. Pass på å telle med linjeskiftene.
Dersom vi blir ferdige med løkken uten å finne en eneste linje som er for lang, er svaret True
.
Del B
Skriv funksjonen good_style_from_file(filename)
som leser inneholdet i filen filename og returerer True hvis inneholdet har god kodestil (alle linjene har mindre enn eller lik 80 tegn), False
hvis ikke. Kjør koden din på filene test_file1.py, test_file2.py og test_file3.py.
Test koden din ved å legge til disse linjene nederst i filen:
print("Tester good_style_from_file... ", end="")
assert(good_style_from_file("test_file1.py"))
assert(not good_style_from_file("test_file2.py"))
assert(not good_style_from_file("test_file3.py"))
print("OK")
Mulige ord
I denne oppgave skal vi ta utgangspunktet fra oppgaven ordspill fra lab5. Det er lurt å løse den oppgaven først.
I filen possible_words.py skriv en funksjon possible_words_from_file(path, letters)
som tar inn en filsti path
til en fil som inneholder en ordliste med ett lovlig ord på hver linje, samt en bokstavsamling letters
. La funksjonen returnere en liste med alle ord man kan lage av de gitte bokstavene.
For å teste funksjonen kan du laste ned den offisielle ordlisten fra Norsk Scrabbleforbund (nsf2022.txt) og legge den i samme mappe possible_words.py kjøres fra.
Husk at hvilken mappe du kjører fra ikke alltid er den samme mappen hvor programmet ligger; men dersom du åpner VSCode i samme mappe som skriptet ditt, vil dette også være den mappen du kjører programmet fra.
Test koden din ved å legge til disse linjene nederst i filen:
print("Tester possible_words_from_file... ", end="")
assert(['du', 'dun', 'hu', 'hud', 'hun', 'hund', 'nu', 'uh']
== possible_words_from_file("nsf2022.txt", "hund"))
# Ekstra test for varianten hvor det er wildcard i bokstavene
# assert(['a', 'cd', 'cv', 'e', 'i', 'pc', 'wc', 'æ', 'å']
# == possible_words_from_file("nsf2022.txt", "c*"))
print("OK")
Bestått
For veldig lenge siden i en galakse langt, langt borte var det en gang en emneansvarlig som skulle avgjøre hvem som skulle få ta eksamen. Data om studentene var samlet i en semikolon-separert csv-fil du kan laste ned her: course_data.csv. I denne filen står B for bestått, mens alle andre verdier betyr ikke bestått.
Reglene for å få ta eksamen var som følger:
- Alle quizer måtte være bestått
- Minst 6 av 11 lab’er måtte være bestått
- Minst 3 av de 5 siste lab’ene måtte være bestått
- Dersom man har bestått kartleggingsprøven telles det som å ha bestått de 6 første labene
Emneansvarlig ønsker å skrive en funksjon som leser csv-filen og returnerer en liste med id til dem som fikk bestått. Kunne du hjulpet ham?
I filen passed.py skriv en funksjon students_who_passed(path)
som leser csv-filen over og returnerer en liste med id’er for de studentene som har bestått arbeidskravene i kurset.
Test koden din ved å legge til disse linjene nederst i filen:
print("Tester students_who_passed... ", end="")
assert(['abc101', 'abc103', 'abc105', 'abc109', 'abc111', 'abc113']
== students_who_passed("course_data.csv"))
print("OK")