Testi

Testi: testi-miklavzeva-knjiga.py

Naloga

Miklavž ima knjigo, v katero zapisuje, kaj počnejo otroci. Knjiga je takšne oblike:

knjiga = { "Ana": ["pometanje stopnic", "jezikanje", "kuhanje kosila", "pretep z bratom", "pometanje stopnic", "kuhanje kosila"], "Benjamin": ["brisanje mize", "jezikanje", "prepisana naloga", "pretep s sestro"], "Cilka": [], "Dani": ["prepir z mamo", "kuhanje kosila", "kuhanje kosila"], "Eva": ["pretep z bratom", "nenarejena naloga"], "Franc": ["pomivanje posode", "brisanje mize", "pometanje stopnic", "kuhanje kosila", "kuhanje kosila", "pometanje stopnic"], "Greta": ["pometanje stopnic", "jezikanje"], "Helga": ["pometanje stopnic", "jezikanje", "kuhanje kosila", "prepir z mamo", "pometanje stopnic", "kuhanje kosila"], }

Vsako delo prinaša pozitivne ali negativne točke. Točkovalnik je, na primer takšen:

tockovalnik = { 'pometanje stopnic': 3, 'kuhanje kosila': 5, 'pomivanje posode': 3, 'brisanje mize': 1, 'pretep z bratom': -3, 'pretep s sestro': -3, 'prepir z mamo': -5, 'nenarejena naloga': -4, 'prepisana naloga': -7, 'jezikanje': -4 }

Ko pride ustrezni čas leta, otroci pišejo pisma z željami za darila. Tule so cene daril.

cena = { 'sanke': 20, 'zvezek': 5, 'lok za violino': 30, 'barvice': 7, 'bomboni': 3 }

Obvezna naloga

Napiši naslednje funkcije:

  • oceni(dela) dobi seznam del in vrne njihovo skupno vrednost. Tako mora, na primer, oceni(["pretep s sestro", "kuhanje kosila"]) vrniti 2 (ker dobi -3 točke za pretep in +5 za kosilo).
  • povzetek_knjige(stran) dobi del knjige (ali celo knjigo) in vrne slovar, katerega ključi so imena otrok in vrednosti njihove ocene. Tako mora povzetek_knjige(knjiga), pri čemer je knjiga zgornji slovar, vrniti {'Franc': 20, 'Dani': 5, 'Benjamin': -13, 'Eva': -7, 'Helga': 7, 'Ana': 9, 'Cilka': 0, 'Greta': -1}
  • izberi(dela, spisek) dobi seznam otrokovih dejanj in seznam njegovih želja. Vrniti mora množico daril, ki jih bo ta otrok prejel. Otrok prejme le darila, ki si jih želi in katerih cena ne presega števila otrokovih točk. Tako mora izberi(["pometanje stopnic", "pomivanje posode", "kuhanje kosila", "pretep s sestro"], {"zvezek", "lok za violino", "barvice", "bomboni"})

    vrniti {"zvezek", "barvice", "bomboni"}. Vsota teh del je namreč 8, zato otrok ne bo dobil loka za violino, ki stane 30.

  • Kot smo videli, dobi otrok VSA darila, ki si jih želi in katerih posamična cena ne presega števila točk, ki jih je dobil otrok. Napiši funkcijo strosek(dela, spisek), ki prejme enake argumente kot prejšnja funkcija, kot rezultat pa vrne strošek, ki ga bo Miklavžu naredil ta otrok. Torej bo klic strosek(["pometanje stopnic", "pomivanje posode", "kuhanje kosila", "pretep s sestro"], {"zvezek", "lok za violino", "barvice", "bomboni"}) vrnil 15: Miklavž bo temu otroku namreč kupil zvezek, barvice in bombone, kar skupaj stane 5 + 7 + 3 = 15.
  • najpridnejsi_otrok(knjiga) dobi slovar, katerega imena so ključi otrok in vrednosti seznam njihovih del (tako kot gornji slovar knjiga in vrne ime najpridnejšega otroka. Če je najbolj pridnih več, naj vrne ime poljubnega od njih. Če, na primer, damo funkciji kot argument gornjo knjigo, mora vrniti niz Franc, saj ima le-ta največ, 20 točk.
  • Otrok je poreden, če naredi kako delo, ki je kaznovano z vsaj petimi nagetivnimi točkami. Funkcija poreden(dela) naj kot argument prejme seznam del (ne otrok!) in kot rezultat vrne True ali False glede na to, dali je otrok s takimi deli poreden ali ne.
  • Miklavž obdaruje le otroke, ki niso poredni. Napiši funkcijo obdarovani(knjiga), ki prejme slovar, kot je gornja knjiga in vrne množico imen otrok, ki niso poredni. Tako mora obdarovani(knjiga) vrniti {'Eva', 'Franc', 'Cilka', 'Greta', 'Ana'}. Ostali otroci so namreč poredni, ker so naredili katero od dejanj, ki se kaznuje s pet ali več negativnimi točkami.

Upoštevaj, da sta točkovalnik del in cena daril fiksni, "knjigo" pa dobi funkcija kot argument in ni nujno vedno enaka.

Rešitve

Dokler se ne hecamo z izpeljanimi seznami, slovarji in množicami, gre samo za vajo iz - no, ja, neizpeljanih seznamov, slovarjev in množic.

def oceni(dela): v = 0 for delo in dela: v += tockovalnik[delo] return v def povzetek_knjige(stran): povzetek = {} for ime, dela in stran.items(): povzetek[ime] = oceni(dela) return povzetek def izberi(dela, spisek): darila = set() ocena = oceni(dela) for darilo in spisek: if cena[darilo] <= ocena: darila.add(darilo) return darila def strosek(dela, spisek): v = 0 for stvar in izberi(dela, spisek): v += cena[stvar] return v def najpridnejsi_otrok(otroci): naj_otrok = naj_ocena = None for ime, dela in otroci.items(): ocena = oceni(dela) if naj_ocena is None or ocena > naj_ocena: naj_otrok, naj_ocena = ime, ocena return naj_otrok def poreden(dela): for delo in dela: if tockovalnik[delo] <= -5: return True return False def obdarovani(otroci): spisek = {} for ime, dela in otroci.items(): if not poreden(dela): spisek.append(ime) return spisek

Prva funkcija je običajno seštevanje, le da moramo vrednosti, ki jih seštevamo brati iz slovarja (tockovalnik[delo]). Podobne reči počnemo v ostalih. Tudi funkciji najpridnejsi_otrok in poreden tečeta po znanem vzorcu; eden išče maksimalno vrednost (oz. ime, ki ji pripada), drugi pa (upam, da končno neuspešno!) zavaja v past, da bi napisali return False na napačnem mestu.

Dodatna naloga

Vse gornje funkcije napiši v eni vrstici - v tem smislu, kot smo se učili na zadnjih predavanjih.

Če se odločiš reševati dodatno nalogo, ti ni potrebno reševati obvezne, saj je rešitev dodatne očitno hkrati tudi rešitev obvezne.

Rešitev

Tokrat je dodatna naloga preprostejša od obvezne. Vse funkcije so tipičen primer reči, ki jih delamo z generatorji in izpeljanimi rečmi.

def oceni(dela): return sum(tockovalnik[delo] for delo in dela) def povzetek_knjige(stran): return {ime: oceni(dela) for ime, dela in stran.items()} def izberi(dela, spisek): return {darilo for darilo in spisek if cena[darilo] <= oceni(dela)} def strosek(dela, spisek): return sum(cena[stvar] for stvar in izberi(dela, spisek)) def najpridnejsi_otrok(otroci): return max((oceni(dela), ime) for ime, dela in otroci.items())[1] def poreden(dela): return any(tockovalnik[delo] <= -5 for delo in dela) def obdarovani(otroci): return {ime for ime, dela in otroci.items() if not poreden(dela)}
Zadnja sprememba: sreda, 24. marec 2021, 15.50