Rešitev s komentarji
Deljenje
Kot boste spoznali tudi v vlogi učitelja, je včasih težko uganiti, katera naloga bo za učence lahka in katera težka. Deljenje je lep primer. Naloga je zahtevala, da napišete program, ki dela natančno isto, kot počnete, ko pisno delite dve števili. Prav zato se mi je zdelo, da bo posrečena za študente Pedagoške fakultete (pri računalnikarji bi me bilo strah za njihovo zmožnost pisnega deljenja - če sem malo hudoben).
Kar počnemo, ko pisno delimo, je tole:
Ker vemo, da je a manjši od b, bomo začeli z
"0.". Nato v vsakem koraku pomnožimo a z 10,
pogledamo, kolikokrat "gre b v a" in to dodamo v
niz (s += str(a // b)) v a pa ostane, kar pač
ostane (a %= b).
Pri tej nalogi sem pričakoval, da bo večina dobila poceni 20%, vendar se to ni zgodilo. Zakaj, ne vem - ugibam, da preprosto niste znali povezati pisnega deljenja z "algoritmom".
Prednik
Tule gre za precej običajno rekurzijo.
Če je oseba otrok prvega, potem je prednik, ki ga iščemo, kar prvi.
Sicer vprašamo vsakega otroka, kdo je prednik osebe
(p = prednik(otrok, oseba)). Če otrok vrne drugega kot
None (pravzaprav bi lahko pisali tudi kar if p:,
vrnemo to reč.
Če funkcija na najde ničesar, tudi ne vrne ničesar, torej vrne
None, kot zahteva naloga.
Zaporedni bomboni
Malenkost napačna rešitev je takšna:
Gremo prek seznama, za vsakega preverimo, ali je enak prejšnjemu in ga, če je tako, dodamo v množico.
Rešitev ne deluje pravilno, ko je i enak 0, saj tedaj primerja
elementa z indeksoma 0 in -1, torej prvi in zadnji element seznama. To lahko
rešimo tako, da začnemo pri prvem, ne ničtem.
Mimogrede, bo kaj narobe, če en in isti element dodamo večkrat? Ne, tole so množice, torej večkratno dodajanje istega elementa nima učinka. Vsak element je v množici le enkrat.
Na predavanjih sem često protestiral proti range(len(nekaj)).
No, dovolil sem ga, kadar v resnici potrebujemo indeks in nam
enumerate ne bi zadoščal. A tudi tu je lepše, če uporabimo zadrgo
na način, ki smo ga spoznali tudi na predavanjih.
Klic zip(imena, imena[1:]) sestavi seznam zaporednih parov in
potem je naša naloga preprosta.
Ko pridemo do sem, pa pravzaprav znamo obrniti funkcijo v učinkovitejšo rešitev v eni vrstici:
Posebnež
Ta naloga je lepa, ker ima toliko različnih rešitev. Moja je bila takšna.
Pripravimo slovar koliko_kdo, katerega ključi so različna
števila bombonov, vrednosti pa seznam otrok, ki ima to število bombonov.
Če imajo, recimo, Ana, Berta in Cilka po tri bonbone, Dani pa štiri, bomo
dobili slovar {3: ["Ana", "Berta", "Cilka"], 4: ["Dani"]}.
V drugi zanki se sprehodimo čez vrednosti v tem slovarju - ključi nas niti ne zanimajo, potrebovali smo jih le, ko smo slovar sestavljali. Pravzaprav vemo, kako bodo videti: ena vrednost bo seznam vseh otrok razen enega, druga vrednost pa seznam s tem otrokom. Poiščemo torej seznam z enim samim elementom in vrnemo prvi (in seveda edini) element tega slovarja.
Zanimiva povsem drugačna rešitev je tale: sestavimo seznam parov (stevilo_bombonov, ime_otroka) in ga uredimo. Posebnež bo zdaj prvi ali zadnji - glede na to, ali ima več ali manj bombonov kot ostali. Če imata prva dva otroka enako bombonov, vrnemo ime zadnjega, sicer ime prvega.
Program je malo zoprn zaradi igre indeksov. Podobnih rešitev je še veliko. Lahko vzamemo, recimo, tri otroke in preverimo, koliko bombonov imajo. Če je eden različen, vrnemo njegovo ime. Če jih imajo vsi trije enako, gremo čez slovar in poiščemo otroka, ki jih nima toliko...
Evidenca bombonov
Število bombonov bo najpreprosteje shranjevati v
defaultdict(int), katerega ključi bodo imena, vrednosti
število bombonov.
Metode so zdaj preproste.
Ne spreglejte, kako lepo smo izračunali vsoto - gre le za vsoto vrednosti
slovarja self.bomboni. Za metodo smo poklicali funkcijo
posebnez iz prejsnje naloge, kot argument pa je dobila slovar.