Stopnice

Naloga je bila bolj za ogrevanje. V v bomo napisali višino, do katere je robot priplezal. Nato gremo po stopnicah in na vsakem koraku preverimo, ali je stopnica previsoka (v tem primeru break), ali pa robot stopi nanjo (v = e).

def kakoVisoko(stopnice): v = 0 for e in stopnice: if e-v > 20: break v = e return v

Za tiste, ki jih zanima: naloga ima tudi lepo rešitev v eni vrstici.

def kakoVisoko(stopnice): return reduce(lambda x,y: x if y-x>20 else y, stopnice, 0)

Eboran

Tudi tule ne bi smelo biti nič težkega, za nekoga, ki je sledil vajam in predavanjem. Standardna rešitev, glede na to, kaj smo sicer počeli pri predmetu, bi bila takšna: razbijemo na besede (split), vsako besedo posebej obrnemo in to zlagamo v nov seznam, nato pa ta seznam spet združimo (join).

def eboran(stavek): s = [] for bes in stavek.split(): s.append(bes[::-1]) return " ".join(s)

Nekoliko učinkoviteje je, če besede kar sami zlagamo v nov niz.

def eboran(stavek): s = "" for b in stavek.split(): s += b[::-1] + " " return s[:-1]

Pri vračanju rezultata odbijemo zadnjo črko, da se znebimo odvečnega presledka na koncu.

Kdor si je kaj pogledal izpeljevanje seznamov, pa je lahko brez prevelikega tuhtanja napisal takole:

def eboran(stavek): return " ".join(x[::-1] for x in stavek.split())

Dodatna naloga je zanimiva, ker jo je težko rešiti drugače, kot z enim zamahom. Potrebno je poznavanje regularnih izrazov; z njimi je rešitev trivialna.

import re def eboran2(stavek): return re.sub("\w*", lambda x:x.group()[::-1], stavek)

Križanka

Ta naloga je pa nekoliko bolj zamotana: če jo hočemo rešiti kolikor toliko preprosto, moramo znati uporabiti else za for.

def krizanka(beseda, besede): ustrezne = [] for b in besede: if len(b) == len(beseda): for i in range(len(b)): if beseda[i]!="." and beseda[i]!=b[i]: break else: ustrezne.append(b) return ustrezne

Če naletimo na črko, v kateri se besedi ne ujemata (beseda[i]!="." and beseda[i]!=b[i]), prekinemo zanko (break). Če se zanka prekine, pa se ne bo izvedel else in besede ne dodamo v seznam.

Kdor tega ni znal, je ravnal pametno, če je sledil namigu in nalogo rešil z dvema funkcijama.

def seUjemata(vzorec, beseda): if len(vzorec) != len(beseda): return False for i in range(len(vzorec)): if vzorec[i]!="." and vzorec[i]!=beseda[i]: return False return True def krizanka(beseda, besede): ustrezne = [] for b in besede: if seUjemata(beseda, b): ustrezne.append(b) return ustrezne

Drugo funkcijo se da napisati tudi krajše, takole.

def krizanka(beseda, besede): return [b for b in besede if seUjemata(beseda, b)]

Kot se spodobi, so tu še rešitve v eni vrstici. Prva uporablja funkcijo all: o njej se nismo pogovarjali, vendar jo je koristno poznati. Kaj dela, lahko uganete ali pa si ogledate v dokumentaciji.

def krizanka(beseda, besede): return [d for d in besede if len(d) == len(beseda) and all(c1 == '.' or c1 == c2 for c1, c2 in zip(beseda, d))]

Druga, nekoliko grša in neučinkovitejša rešitev se ji izogne.

def krizanka(beseda, besede): return [d for d in besede if len(d) == len(beseda) == sum(c1 in c2+"." for c1, c2 in zip(beseda, d))]

Popularni rojstni dnevi

Naloga spominja na eno od nalog na vajah, kjer smo se učili uporabe slovarjev in šteli najbolj pogoste besede. Tu pač štejemo datume, ostalo je podobno.

Pa rešimo nalogo nekoliko drugače. Pripravimo seznam, v katerem bo za vsak datum pisalo, koliko ljudi ima tedaj rojstni dan. V, na primer, dnevi[405] bo pisalo, koliko dni ima rojstni dan četrtega maja. Največji indeks v tabeli bo 3112, to je 31. december.

def histogramDni(imedat): dnevi = [0]*3113 for l in file(imedat): dnevi[int(l[:4])] += 1 for d, c in enumerate(dnevi): if c: print "%2i.%2i. %i" % (d / 100, d % 100, c)

Gre pa tudi krajše.

def histogramDni(imedat): dnevi = [e[:4] for e in file(imedat)] for dan in set(dnevi): print "%s.%s. %i" % (dan[:2], dan[2:4], dnevi.count(dan))

dnevi je seznam dni (v obliki nizov, prvih štirih črk EMŠO). Nato gremo prek množice elementov tega seznama (tako se znebimo duplikatov in izpišemo število pojavitev posameznega dne.

Krajše bi lahko napisali:

def histogramDni(imedat): print "\n".join("%s.%s. %i" % (dan[:2], dan[2:4], [e[:4] for e in file(imedat)].count(dan)) for dan in set(e[:4] for e in file(imedat)))

Slabost te rešitve je, da znova in znova bere datoteko. Tako se ne dela. :)

Stirlingova števila drugega reda

Naloga ni bila posebej popularna in pravilnih rešitev praktično ni bilo, kar je nenavadno, saj je naloga skoraj enaka (in celo nekoliko lažja) kot naloga, ki smo jo reševali na vajah in katere rešitev je bila tudi objavljena (http://ucilnica.fri.uni-lj.si/mod/resource/view.php?id=9780).

Rešitev je lahko, recimo, takšna

def stirling2(n ): print " 1" for i in range(n-1): ns = [1] for j in range(1, i+1): ns.append(s[j-1]+(j+1)*s[j]) ns.append(1) print " ".join("%4i" % t for t in ns) s = ns

Tako kot Pascalov trikotnik je mogoče tudi tole narediti v eni vrstici, vendar je to grdo in nesmiselno. (Če se hoče kdo igrati: zunanjo zanko je potrebno zamenjati z reduce.

Celoten izpit

Tule je rešitev vseh nalog izpita na nivoju, ki ne presega tega, kar smo predavali.

def kakoVisoko(stopnice): v = 0 for e in stopnice: if e-v > 20: break v = e return v def eboran(stavek): return " ".join(x[::-1] for x in stavek.split()) def krizanka(beseda, besede): ustrezne = [] for b in besede: if len(b) == len(beseda): for i in range(len(b)): if beseda[i]!="." and beseda[i]!=b[i]: break else: ustrezne.append(b) return ustrezne def histogramDni(imedat): dnevi = [0]*3113 for l in file(imedat): dnevi[int(l[:4])] += 1 for d, c in enumerate(dnevi): if c: print "%2i.%2i. %i" % (d / 100, d % 100, c) def stirling2(n ): print " 1" for i in range(n-1): ns = [1] for j in range(1, i+1): ns.append(s[j-1]+(j+1)*s[j]) ns.append(1) print " ".join("%4i" % t for t in ns) s = ns

Tole pa je še rešitev prek bližnjic.

def kakoVisoko(stopnice): return reduce(lambda x,y: x if y-x>20 else y, stopnice, 0) def eboran(stavek): return " ".join(x[::-1] for x in stavek.split()) def krizanka(beseda, besede): return [d for d in besede if len(d) == len(beseda) == sum(c1 in c2+"." for c1, c2 in zip(beseda, d))] def histogramDni(imedat): print "\n".join("%s.%s. %i" % (dan[:2], dan[2:4], [e[:4] for e in file(imedat)].count(dan)) for dan in set(e[:4] for e in file(imedat))) def stirling2(n ): print " 1" for i in range(n-1): ns = [1] for j in range(1, i+1): ns.append(s[j-1]+(j+1)*s[j]) ns.append(1) print " ".join("%4i" % t for t in ns) s = ns
Zadnja sprememba: sreda, 10. avgust 2011, 10.20