Testi

Testi: testi-cebelja-statistika.zip

Naloga

V nalogi se bomo ukvarjali kar s čebelarjenjem, saj ste se v prejšnji nalogi dodobra spoznali s čebeljim zapisom količine nektarja v cvetovih.

Bistvo te domače naloge je, da vse rešitve napišete v eni sami vrstici. Vse funkcije morajo biti takšne:

def ime_funkcije(argumenti):
    return tule_pise_kar_pac_mora_pisati

Ogrevalni nalogi

V ogrevalnih nalogah ne pozabite, da ima Python funkciji sum(s) in max(s), ki vrneta vsoto elementov seznama s in njegov največji element.

Vsota po vrstah

Napiši funkcijo po_vrstah(vrt), ki vrne seznam vsot količin nektarja po vseh vrstah. Torej, po_vrstah([[3, 5, 1], [1, 1, 1], [2, 0, 4]]) mora vrniti [9, 3, 6].

Najboljši v vrsti

Napiši funkcijo najboljsi(vrt), ki vrne seznam z maksimalnimi količin nektarja po vseh vrstah. Torej, najboljsi([[3, 5, 1], [1, 1, 1], [2, 0, 4]]) mora vrniti [5, 1, 4].

O teh nalogi ni izgubljati besed: prva zahteva seznam vsot, druga seznam maksimumov vrstice - za vsako vrstico v vrtu. Ali, v Pythonu

def po_vrstah(vrt): return [sum(vrsta) for vrsta in vrt] def najboljsi(vrt): return [max(vrsta) for vrsta in vrt]

Obvezne naloge

Apis diagonalicus

Napiši funkcijo diagonala(vrt), ki pove, koliko naberejo čebele vrste Apis diagonalicus, ki gredo čez vrt vedno po diagonali, (0, 0), (1, 1), (2, 2), ...), dokler ne pridejo do roba. Klic po_diagonali([[3, 5, 1], [1, 1, 1], [2, 0, 4]]) mora vrniti 8 (to je, 3 + 1 + 4).

Sešteti moramo torej vrt[i][i] za vsak i od 0 do - koliko? Do len(vrt) ali len(vrt[0])? Do tistega, kar je manjše; čebela bo šla po diagonali in se ustavi, ki ji zmanjka bodisi vrstic bodisi stolpcev.

def diagonala(vrt): return sum(vrt[i][i] for i in range(min(len(vrt), len(vrt[0]))))

Palindromni vrt

Napiši fukcijo je_palindromen, ki pove, ali je vrt palindromen. Vrt je palindromen, če so vse njegove vrste palindromi. Spomnite se, kako v Pythonu hitro ugotovimo, ali je nek niz (ali seznam, saj je isto) palindrom.

Ali je neka vrsta palindromna, preverimo z vrsta == vrsta[::-1]. Funkcija mora preveriti, ali to velja za vsako vrsto v vrtu (for vrsta in vrt), torej

def je_palindromen(vrt): return all(vrsta == vrsta[::-1] for vrsta in vrt)

Palindromne vrste

Napiši fukcijo palindromne, ki vrne vse palindromne vrste v vrtu. (Povedano bližje Pythonu: vrniti mora seznam vseh tistih vrstic, ki so palindrome.) Tako mora palindromne([[1, 2, 2, 1], [1, 2, 3, 4], [0, 7, 7, 0], [0, 0, 0, 1]]) vrniti [[1, 2, 2, 1], [0, 7, 7, 0]].

Besedilo naloge je že izdalo vse.

def palindromne(vrt): return [vrsta for vrsta in vrt if vrsta == vrsta[::-1]]

Dodatne naloge

Dodatne naloge so zahtevale dvojne zanke.

Branje datotek

Čebele shranjujejo stanje vrtov v datoteke. Nekaj primerov najdete na Učilnici. Napišite funkcijo preberi_vrt(ime_dat), ki prebere datoteko s podanim imenom ime_dat in vrne vsebino v takšni obliki kot, so navadno zapisani vrtovi (s seznamom seznamov).

Če imamo nek niz števil, ločenih z vejico, naredimo iz njega seznam števil tako: [int(x) for x in vrsta.split(",")]. Druga možnost - o kateri se sicer nismo učili - je, da uporabimo funkcijo map, takole: map(int, vrsta.split(",")). Čeprav je map krajši, so izpeljani seznami pogosto hitrejši, predvsem pa jih imamo za lepše.

Zdaj, ko vemo, kako predelati eno vrstico, to storimo z vsemi vrsticami iz datoteke:

def preberi_vrt(ime_dat): return [[int(x) for x in vrsta.split(",")] for vrsta in open(ime_dat)]

Nekateri so tu pisali for vrsta in open(ime_dat).read().splitlines(), vendar to ni potrebno; če spustimo zanko for čez datoteko, počne natančno isto, kot če se sami zafrkavamo s splitlines (pa še manj pomnilnika pokuri).

Apis vraževernikus

Recimo, da imamo že napisano funkcijo

def prastevilo(n): return all(n % i != 0 for i in range(2, n))

ki pove, ali je podano število n praštevilo (funkcija, čisto preprosto, pove, ali so ostanki po deljenju n z i različni od 0 za vse i-je od 2 do n-1).

Napiši funkcijo prastevilski(vrt), ki kot argument dobi vrt in kot rezultat vrne vrt, v katerem so čebele obrale vse cvetove razen tistih, v katerih je količina nektarja praštevilo. (Gre namreč za vrsto Apis vraževernikus, ki se takšnih cvetov boji.) Z drugimi besedami, vsa sestavljena števila nadomestite z 0.

Klic prastevilski([[3, 5, 1], [7, 8, 12], [9, 3, 4]]) mora vrniti [[3, 5, 1], [7, 0, 0], [0, 3, 0]].

Če bi naloga zahtevala, da to naredimo samo z navadnim seznamom vrsta, bi pisali [x if prastevilo(x) else 0 for x in vrsta], to je, hočemo seznam, ki za vsak x vsebuje x, če je x praštevilo, in 0, če ni.

Zdaj pa, tako kot prej, to naredimo prek vseh vrst.

def prastevilski(vrt): return [[x if prastevilo(x) else 0 for x in vrsta] for vrsta in vrt]

Apis vraževernikus (2)

Napiši funkcijo vrazevernikus(vrt), ki pove, koliko nektarja nabere vraževerna čebela, če v podanem vrtu obere vse, kar si upa.

Tole je isto kot prej, le da ne ustvarjamo seznamov, temveč računamo vsote.

def vrazevernikus(vrt): return sum(sum(x for x in vrsta if not prastevilo(x)) for vrsta in vrt)

Povsod kaj praznega

Napiši funkcijo povsod_0(vrt), ki pove, ali je v vsaki vrstici vrta vsaj ena ničla.

V malo grši slovenščini, a bližje Pythonu: za vse vrste morajo veljati, da je vse en njihov element enak 0.

def povsod_0(vrt): return all(any(x == 0 for x in vrsta) for vrsta in vrt)

Vedno več

Napiši funkcijo vedno_vec(vrt), ki pove, ali je res, da je v vrtu v vsaki naslednji vrsti vsaj toliko nektarja kot v prejšnji (torej, vsota nektarja v prvi vrstici mora biti večja ali enaka vsoti v ničti, vsota v drugi večja ali enaka vsoti v prvi in tako naprej). Namig: zip(vrt, vrt[1:]).

Namignjeni zip nam sestavi natančno pare, ki jih moramo primerjati - ničtega in prvega, prvega in drugega, drugega in tretjega... Prvi element iz para mora biti manjši ali enak drugemu za vse pare:

def vedno_vec(vrt): return all(sum(x) <= sum(y) for x, y in zip(vrt, vrt[1:]))

Vedno več ali manj

Napiši funkcijo vedno_vec_ali_manj(vrt), ki pove, ali je res, da je količina nektarja po vrsti nepadajoča (kot v prejšnji funkciji) ali pa nenaraščajoča (tako, da je v vsaki naslednji vrstici kvečjemu toliko nektarja kot v prejšnji.

Trik te naloge je v tem, da se je ne da rešiti tako, kot bi morda naivno naredili na prvi pogled.

# To ne deluje! def vedno_vec(vrt): return all(sum(x) <= sum(y) or sum(x) >= sum(y) for x, y in zip(vrt, vrt[1:]))

Težava je v tem, da je pogoj vedno resničen, saj bo prva vsota manjša ali pa večja od druge (ali pa celo enaka, obakrat ;).

Najbrž je najboljše, kar lahko storimo, to, da združimo prejšnjo funkcijo in obrnjeno.

def vedno_vec_ali_manj(vrt): return all(sum(x) <= sum(y) for x, y in zip(vrt, vrt[1:])) or \ all(sum(x) >= sum(y) for x, y in zip(vrt, vrt[1:]))

Kot pravilno rešitev bi priznali tudi tole duhovitost:

def vedno_vec_ali_manj(vrt): return vedno_vec(vrt) or vedno_vec(vrt[::-1])

Če bi bil prehod prek seznama "drag" (ker je seznam velik ali pa, recimo, ne gre za seznam temveč za datoteko, ki jo sproti beremo, ali za podatke, ki jih sproti dobivamo iz baze), bi se morali potruditi sprogramirati funkcijo tako, da gre prek seznama le enkrat. Razmislite, kako.

Zadnja sprememba: sreda, 24. marec 2021, 15.47