Dudleyeva darila
Ogrevanje: Preštevanje daril
Dudley je za rojstni dan dobil darila, katerih imena je zložil v seznam, recimo
["avto", "lok", "avto", "avto", "bomboni", "lok"]. Napiši funkcijo
prestej(s), ki dobi takšen seznam in vrne slovar, katerega ključi so imena
daril, pripadajoče vrednosti pa število kosov tega darila. Za gornji seznam
bi funkcija vrnila {"avto": 3, "lok": 2, "bomboni": 1}.
Rešitev
Če mora funkcija vrniti slovar, mora najprej narediti slovar. Prazen slovar. Nato gremo čez darila. Če je že dobil kakšno takšno darilo, povečamo števec. Če ni, ga vstavimo v slovar in zabeležimo, da je dobil en izvod tega darila.
def prestej(darila):
stevila = {}
for darilo in darila:
if darilo in stevila:
stevila[darilo] += 1
else:
stevila[darilo] = 1
return stevila
Nekega lepega dne vam bom pokazal collections.defaultdict ali celo
collections.Counter in vaše življenje bo naenkrat lepše.
Obvezna naloga: Seštevanje daril
V posameznem paketu je lahko več daril - a vedno iste vrste, da ne bi bilo
zmede. Tako je dobil, recimo paket z dvema avtoma, paket z dvema lokoma,
paket s štirimi avti, paket z enim avtom, paket z 42 bomboni in paket s tremi
loki, ali, v Pythonu:
[("avto", 2), ("lok", 2), ("avto", 4), ("avto", 1), ("bomboni", 42), ("lok", 3)].
Napiši funkcijo sestej(darila), ki dobi seznam v tej obliki in vrne podoben
slovar kot v ogrevalni nalogi, torej, {"avto": 7, "lok": 5, "bomboni": 42}.
Poleg tega napiši funkcijo stevilo_daril(darila), ki prejme takšen slovar
daril (recimo {"avto": 7, "lok": 5, "bomboni": 42}) in vrne skupno število
daril (v gornjem primeru 54, to je 7 + 5 + 42).
Napiši tudi funkcijo razlicnih_daril(darila), ki dobi takšen slovar in vrne
število različnih daril - v gornjem primeru 3.
Poleg tega napiši funkcijo cena(darila, cene), ki prejme takšen slovar in
slovar s cenami različnih daril, vrne pa njihovo skupno ceno. Če pokličemo,
recimo,
cena({"avto": 7, "lok": 5, "bomboni": 42},
{"avto": 3, "lok": 5, "bomboni": 1, "dron": 10})
(avto stane 3 evre, lok 5, bombon 1, dron 10), je skupna cena daril 88
(7 * 3 + 5 * 5 + 42 * 1).
Rešitev
Podobna reč, le da ne gremo prek daril, temveč prek parov daril in količin.
Namesto, da bi povečevali za 1 (oz. postavljali na 1), povečujemo za
(in postavljamo na) kolicina.
def sestej(darila):
stevila = {}
for darilo, kolicina in darila:
if darilo in stevila:
stevila[darilo] += kolicina
else:
stevila[darilo] = kolicina
return stevila
Če vemo, da stevila.values() vrne vse vrednosti in da funkcija sum sešteje,
kar ji damo, je preštevanje vseh daril trivialno.
def vseh_daril(stevila):
return sum(stevila.values())
Število različnih daril je kar število ključev v slovarju. Vsak ključ je namreč unikaten.
def stevilo_daril(stevila):
return len(stevila)
Za računanje cene gremo prek parov daril in kosov. Za to uporabimo
stevila.items(). Za vsako darilo pogledamo, koliko stane; to imamo,
priročno, zapisano v cene[darilo]. Ceno pomnožimo s številom kosov in
prištejemo k vsoti.
def cena(stevila, cene):
vsota = 0
for darilo, kosov in stevila.items():
vsota += kosov * cene[darilo]
return vsota
Po pričakovanjih vas je precej sprogramiralo funkcijo cena takole:
def cena(darila, cene):
cena=0
for darilo, kosov in cene.items():
for darilo1, cena in darila.items():
if darilo == darilo1:
cena += kosov * cena
return cena
Notranja zanka je počasna in nepotrebna. Slovarje imamo prav zato, da nam je ne bi bilo potrebno pisati.
Dodatna naloga: Napredek
Dudley je, kot je znano, občutljiv na to, koliko daril prejme. Napiši funkcijo
napredek(lani, letos), ki prejme dva slovarja - prvi vsebuje lanska darila,
drugi letošnja funkcija naj vrne slovar, katerega ključi so imena daril,
katerih število je letos drugačno kot lani, pripadajoče vrednosti pa povedo,
za koliko. Če pokličemo
napredek({"avto": 3, "lok": 5, "bomboni": 3, "dron": 1},
{"avto": 8, "lok": 3, "bomboni": 3, "čokolada": 2})
Funkcija vrne
{"avto": 5, "lok": -2, "dron": -1, "čokolada": 2}
Ne spreglej, da slovar ne vsebuje bombonov, saj jih je prejel toliko kot lani.
Rešitev
Najprej naredimo kopijo letošnjega slovarja, saj ga bomo spreminjali.
Nato gremo prek lanskega slovarja. Za vsako darilo preverimo, ali ga je dobil
tudi letos. Če ga je, potem od razlika odštejemo število kosov, ki jih je
dobil lani. Če je število kosov s tem padlo na 0, pobrišemo to darilo iz
slovarja.
Če tega darila letos ni dobil, pa zabeležimo, da je razlika -kosov.
def napredek(lani, letos):
razlika = letos.copy()
for darilo, kosov in lani.items():
if darilo in razlika:
razlika[darilo] -= kosov
if not razlika[darilo]:
del razlika[darilo]
else:
razlika[darilo] = -kosov
return razlika
Rešitve, kot se jih bomo učili kmalu
def prestej(s):
return {x: s.count(x) for x in s}
def sestej(darila):
return {darilo: sum(y for x, y in darila if x == darilo) for darilo, _ in darila}
def vseh_daril(darila):
return sum(darila.values())
def razlicnih_daril(darila):
return len(darila)
def cena(darila, cene):
return sum(stevilo * cene[darilo] for darilo, stevilo in darila.items())
def napredek(lani, letos):
return {x: letos.get(x, 0) - lani.get(x, 0) for x in set(letos) | set(lani) if letos.get(x, 0) != lani.get(x, 0)}