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)}
Zadnja sprememba: torek, 24. februar 2026, 17.53