Opravljivke
Opravljivke
Bistvo domače naloge je bilo delo s slovarji in množicami. Če veste, kaj je bistvo slovarjev (to, da lahko preverim, ali obstaja določen ključ in da lahko hitro dobim vrednost, ki pripada ključu) ter če veste, kaj se da delati z množicami (računati unije, preseke, razlike...) so bile naloge lahke. Kdor v slovarjih in množicah vidi samo nekoliko drugačne sezname, je naloge vseeno lahko rešil, vendar se je z njimi nekoliko (ali veliko) več mučil. In to, da mora funkcija vračati takšen in takšen slovar, mu ni bilo v pomoč, temveč v napoto.
V nalogi se bomo ukvarjali z nekakšnimi mrežami. Za začetek si lahko predstavljamo, da gre za opravljivke, ki vsako novico sporočijo natančno eni osebi; Ana, na primer, vse izčveka Cilki, Berta prav tako pripoveduje Cilki, Dani Emi, Ema Fanči in Greta Fanči. Cilka in Fanči začuda vse obdržita zase.
![]()
Takšno mrežo bomo predstavili s slovarjem
čveke = {"Ana": "Cilka", "Berta": "Cilka", "Dani": "Ema", "Ema": "Fanci", "Greta": "Fanci"} Naredimo lahko tudi bolj zapletene mreže, na primer spodnji sistem cevi. V eno od cevi vržemo kroglico, zanima pa nas, kje prileti ven. Kroglico lahko vstavimo tudi na kateremkoli križišču ali celo na koncu (vstavimo jo na "o" in prileti iz "o").
![]()
Slovar zanjo je takšen:
cevi = {"a": "b", "b": "o", "c": "o", "d": "x", "e": "q", "g": "k", "h": "o", "i": "q", "j": "F", "l": "w", "m": "B", "n": "z", "p": "f", "q": "b", "r": "t", "s": "f", "t": "k", "u": "s", "v": "t", "x": "g", "y": "g", "z": "m", "A": "r", "C": "y", "D": "p", "E": "l", "F": "m", "w": "B"}
Ogrevanje: Od kod kam
Napišite funkcijo
kam(cevi, cev). Prvi argument je slovar s sistemom, kot sta, recimo, gornja, drugi pa začetna cev. Če pokličemo, denimo,kam(čveke, "Dani")mora vrniti"Fanči"in če pokličemokam(cevi, "r")mora vrniti"k".
Gre za osnovno nalogo iz slovarjev: potrebno je preveriti, ali slovar
vsebuje določen ključ in priti do vrednosti pri tem ključu. Nekateri ste se
ubijali s tem, da ste pisali zanko for prek
cevi.items() in s tem počeli ravno tisto, čemur se z uporabo
slovarjev izognemo: slovarje imamo prav zato, da lahko na preprost način
pridemo do tistega, kar je shranjeno pod določenim ključem.
Sam postopek, ki ste ga morali sprogramirati, je takšen.
Dokler podana cev kam vodi (kar vemo po tem, da se pojavi med ključi v
slovarju, kar preverimo s cev in cevi), gremo v to cev
(cev = cevi[cev]). Ko je konec, vrnemo cev, kjer smo se ustavili
(return cev).
Kot sem napisal tudi na forumu, so si nekateri zapletli življenje z metodo
get, takole
Metodo get uporabim takrat, predvsem takrat in skoraj samo
takrat, kadar želim dodati še privzeto vrednost. V gornjem kontekstu pa je le
nerodna.
Nekateri (pravzaprav večina) ste uvedli "trenutno" cev:
Ni narobe. Potrebno pa tudi ne.
Ocena 6: Koliko kam
Napišite funkcijo
koliko_kam(cevi, zacetne), ki dobi slovar s sistemom in seznam začetnih pozicij ter vrne slovar, ki pove, kolikokrat smo končali na določenem mestu. Če pokličemo, recimokoliko_kam(čveke, ["Ana", "Ana", "Greta", "Berta", "Cilka"]), mora vrniti{"Cilka": 4, "Fanci": 1}.
Tole je klasična naloga iz slovarjev: preštevanje. Seveda je zelo koristilo,
če ste se spomnili na defaultdict. Mislim, da sem vsaj
vsakemu, ki je pisal po nasvet, svetoval, naj ga uporabi.
Še en razlog, zakaj sem vam dal to nalogo, je, da se učite uporabiti
funkcije, ki jih že imate. Tisti, ki v tej funkciji niso klicali funkcije
kam, ki so jo napisali v prejšnji nalogi, so morali tule ponoviti
vse iz prejšnje naloge, zato je bila funkcija bolj zapletena, kot bi lahko bila.
In z njo ste se bolj mučili. Preprosta rešitev je torej:
Grem prek vseh podanih cevi, za vsako ugotovim, kam vodi in pri tej, slednji cevi, povečam števec za 1.
Malenkost daljša varianta je
Če se niste spomnili na default_dict, ste morali narediti nekaj
takšnega:
Ocena 7: Najpogostejša
Napišite funkcijo
najpogostejsa(cevi, zacetne), ki deluje podobno kot prejšnja, le da vrne najpogostejši izhod. Če pokličemonajpogostejsa(čveke, ["Ana", "Ana", "Greta", "Berta", "Cilka"]), mora vrniti"Fanci".
Domače naloge so en dolgčas. Tudi tole ste že videli: poiskati ključ, ki pripada največji vrednosti. Če je niste videli v točno tej obliki, ste jo pa v kakšni drugi: opazovati moramo velikost nečesa, vrniti pa nekaj, na kar se ta velikost nanaše.
Vzorec ste videli že večkrat. Tule je ena od izvedenk.
V začetku postavi naj na None, kar mi bo povedalo,
da nisem pogledal še nobene cevi. Potem izračunam, koliko jih gre kam (pri čemer
seveda uporabim prejšnjo funkcijo). Nato grem čez vse pare končnih cevi in
njihovih števcev. V pogoju poglejmo najprej drugi del,
koliko > kolikam[naj]: če je v "to" končno cev
(katera) prišlo več krogel kot v tisto, v katero jih je prišlo
največ, si zapomnim, da jih je prišlo največ v to (naj = katera).
To bi bilo lepo in prav, samo za prvo cev ne deluje. Na kaj naj postavim
naj v začetku? Ena možnost je torej narediti, kot smo naredili: v
začetku ga postavimo na None in potem še preden preverimo ali je
koliko > kolikam[naj], preverimo, ali je naj slučajno
None. Če je, potem si seveda zapomnimo to cev kat najpopularnejšo,
saj je pač prva doslej.
Mimogrede, nisem napisal naj == None temveč
naj is None. Kakšna je razlika, smo se učili takrat, ko smo risali
škatlice. V tem primeru je v bistvu ni. Po nekih pravilih lepega vedenja v
Pythonu pa je zaželeno, da takrat, kadar imamo samo en objekt določene vrste
(takšni so, recimo, None, False in True
- vsi Trueji, recimo, niso samo enaki Trueji temveč
celo isti Trueji) uporabljamo is in ne
==. Samo toliko, da veste in da vas ne bo začudilo, ko me boste
videli početi to reč. Če boste sami uporabljali ==, ni nič narobe.
Ocena 8: Vir in ponor
Napišite funkciji
zacetne(cevi)inkoncne(cevi). Prva naj vrne množico vseh cevi, ki nimajo vhodov, druga vse, ki so na koncu. Tako morazacetne(čveke)vrniti{"Ana", "Berta", "Dani", "Greta"},koncne(čveke)pa{"Cilka", "Fanči"}.
Tale je pa najpreprostejša - če vemo, da so začetne cevi vse tiste, ki se pojavljajo med ključi, ne pa tudi med vrednostmi, končne pa tiste, ki se med vrednostmi in ne med ključi. (Razmislite, pa boste videli, da je tako. Poleg tega sem to, se mi zdi, povedal na predavanjih. ;)
Takšne reči se lepo pove z množicami. Ergo,
Osebno mi je sicer všečnejše brez nepotrebnega keys().
Ta naloga je bila v bistvu naloga, ki je preverjala, ali se spomnite, kaj vse se da narediti z množicami. Tisti, ki se ne, ste si sami krivi, če ste se ubijali s kakšnimi groznimi zankami.
Ocena 9: Viri
Napišite funkcijo
viri(cevi), ki vrne slovar, katerega ključi so končne cevi, vrednosti pa množice vseh točk, ki vodijo v to cev. V primeru opravljivk nas bosta ključa tisti dve, ki držita jezik za zobmi, pripadajoči vrednosti pa množici tistih, ki jih zalagata (posredno ali neposredno) z informacijami. Torej,viri(čveke)mora vrniti{"Cilka": {"Ana", "Berta", "Cilka"}, "Fanci": {"Dani", "Ema", "Fanci", "Greta"}}.
V tej nalogi ste morali kombinirati množice in slovarje. Spet vam je lahko
zelo pomagal defualtdict.
Kar moramo narediti, je preprosto, le v pravo smer moramo razmišljati. Nekateri ste začeli s končnimi cevmi in razmišljali, na kakšne načine je mogoče priti do njih. Za to smer je potrebno obračati slovar in se iti rekurzijo (ne čisto nujno, ampak drugi načini so lahko še bolj zoprni).
Veliko lažje pa je v drugo smer: za vsako cev - bodisi začetno, končno ali karkoli vmes - pogledamo, kam pelje. Potem v množico, ki pripada tisti kam-pelje cevi dodamo cev, iz katere smo začeli.
Če vam ni padlo v oči, vas opozarjam na nenavadni:
cevi.keys() | cevi.values(). To je videti kot unija množic -
vendar cevi.keys() in cevi.values() vendar nista
množici! Kaj je to, bomo izvedeli prav ta teden.
Ocena 10: Zapiši in beri
Napišite funkciji
zapisi(cevi)inpreberi(s). Prva dobi cevi in jih zapiše v obliki niza, takole:Ana>Cilka Berta>Cilka Dani>Ema Ema>Fanci Greta>Fanci Vrstni red vrstic v nizu je poljuben. Druga funkcija
preberi(s)kot argument dobi prav takšen niz in kot rezultat vrne slovar.
Tole je pa bolj tehnična zadeva, saj ne gre toliko za slovarje kot za sestavljanje in razkopavanje nizov.