Na dražbi seveda nimajo tako nepopolnih zapisnikov, kot je namigovala prejšnja naloga. Ve se, katere predmete prodajajo. Na dražbe tudi ne hodita le Ana in Berta; Ani seveda ni treba vedno začeti izklicevanja.
V resnici so zapisniki videti tako:
slika,Berta,31
slika,Ana,33
slika,Berta,35
slika,Fanči,37
slika,Ana,40
slika,Fanči,45
pozlačen dežnik,Ema,29
Meldrumove vaze,Greta,44
Meldrumove vaze,Ana,46
Vsaka vrstica vsebuje tri podatke, ločene z vejico. Prvi je prodajani predmet, drugi je ime osebe, ki viša ceno, in tretji so ponujene cene teh oseb. Pri branju si bomo (lahko) pomagali s tem, da vemo naslednje.
Pri reševanju ne smete predpostavljati, da na dražbi sodelujejo le osebe, ki jih vidite v datoteki in da se prodajajo le ti izdelki. Program mora biti splošen in delovati tudi za datoteko, ki jo bodo na dražbi pripravili jutri - z drugimi predmeti in osebami.
Konkretno, program mora znati obdelati tako "zapisnik.txt" kot "zapisnik-dan2.txt". (Ne vznemirjaj se, če se pri drugem zapisniku spoli oseb ne bodo ujemali in bo Anton kupila to in ono.)
Če želiš pustiti med izpisi prazno vrstico, pokliči
print
brez argumentov - print()
.
Izpis je lahko takšen:
Najdražji predmet je kip - za 107 ga je kupila Dani
slika - 45
pozlačen dežnik - 29
Meldrumove vaze - 78
skodelice - 83
kip - 107
čajnik - 15
srebrn jedilni servis - 63
perzijska preproga - 21
slika - 6
pozlačen dežnik - 1
Meldrumove vaze - 12
skodelice - 12
kip - 29
čajnik - 1
srebrn jedilni servis - 14
perzijska preproga - 2
Najbolj so se pulile za predmet kip
Prva ni raketna znanost. Beremo vrstice in vsako razbijemo na ime osebe, predmeta in ceno. Primerjamo cene in shranjujemo najvišjo ceno in pripadajoči predmet.
= 0
naj_cena for vrstica in open("zapisnik.txt"):
= vrstica.split(",")
kaj, kdo, koliko if int(koliko) > naj_cena:
= int(koliko)
naj_cena = kdo
naj_kdo = kaj
naj_kaj
print("Najdražji predmet je", naj_kaj, "- za", naj_cena, "ga je kupila", naj_kdo)
Najdražji predmet je kip - za 107 ga je kupila Dani
Drugo bomo ugnali s trikom: za vsak predmet shranjujemo vse cene. Ker so ključi v slovarju enkratni (prirejanje vrednosti obstoječemu ključu le spremeni njegovo vrednost), bo v slovarju opisana zadnja cena. Ker se cene le višajo in ker se vsak izdelek prodaja le enkrat, bomo tako imeli zapisano ravno najvišjo ceno. :)
= {}
cene for vrstica in open("zapisnik.txt"):
= vrstica.split(",")
kaj, kdo, koliko = int(koliko)
cene[kaj]
for kaj, koliko in cene.items():
print(kaj, "-", koliko)
slika - 45
pozlačen dežnik - 29
Meldrumove vaze - 78
skodelice - 83
kip - 107
čajnik - 15
srebrn jedilni servis - 63
perzijska preproga - 21
Tretja je klasično preštevanje. Vsakemu predmetu ustreza element slovarja. Če predmet vidimo prvič, ga dodamo v slovar; pripadajoča vrednost, število višanj bo 0. Ob vsaki pojavitvi predmeta povečamo število višanj.
= {}
visanj for vrstica in open("zapisnik.txt"):
= vrstica.split(",")
kaj, _, _ if kaj not in visanj:
= 0
visanj[kaj] += 1
visanj[kaj]
for kaj, koliko in visanj.items():
print(kaj, "-", koliko)
slika - 6
pozlačen dežnik - 1
Meldrumove vaze - 12
skodelice - 12
kip - 29
čajnik - 1
srebrn jedilni servis - 14
perzijska preproga - 2
Isti slovar potem uporabimo za rešitev zadnje obvezne naloge. Podobna je prvi, kjer smo iskali izdelek z najvišjo ponujeno ceno. Tam smo primerjali cene ter si zapomnili najvišje cene in pripadajoče predmete. Tu pa gremo čez slovar, ki pove število ponudb za posamezni izdelek in si zapomnimo največje število ponudb in pripadajoči predmet. Razlika je le v tem, da smo tam podatke brali z datoteke, tu pa jih dobivamo iz slovarja.
= None
naj_zelena for kaj, koliko in visanj.items():
if naj_zelena is None or visanj[kaj] > visanj[naj_zelena]:
= kaj
naj_zelena
print("Najbolj so se pulile za predmet", naj_zelena)
Najbolj so se pulile za predmet kip
Nedvomno se bodo pojavile tudi takšne rešitve.
print("Najbolj so se pulili za predmet", max(visanj, key=visanj.get))
Najbolj so se pulili za predmet kip
To boste dobili na Stack Overflowu, ChatGPTju ali od prijatelja, ki
pozna Python. Ne počnite tega. Na ta način se ne naučite ničesar. Razen,
če razumete, da so metode Pythona prvorazredni objekti in kaj počne
max
s poimenskim argumentom key
. Sicer pa
uporaba takšnih rešitev, četudi jih izbrskate sami, ni nič bolj poučna,
kot če vam nalogo reši kdo drug.
O takšnih rešitvah se bomo učili, vendar takrat, ko bomo pametnejši in jih bomo tudi razumeli. Dotlej pa za vajo raje pišimo zanke in pogoje, saj nam bodo prišli prav takrat, ko hitrejših rešitev ne bo.
Izpis bi lahko bil takšen:
Poraba po osebah:
Berta - 98
Cilka - 78
Dani - 107
Ema - 29
Fanči - 45
Greta - 63
Helga - 21
Dviganje cen:
slika - 14
pozlačen dežnik - 0
Meldrumove vaze - 34
skodelice - 33
kip - 77
čajnik - 0
srebrn jedilni servis - 36
perzijska preproga - 5
Nalogi bo preprosteje rešiti hkrati. Sestavili bomo tri slovarje. Vsi bodo imeli za ključe predmete.
prvic
bo za vsak izdelek vseboval njegovo prvo
ceno,zadnjic
bo vseboval zadnjo ceno,kupec
bo vseboval končnega kupca.= {}
prvic = {}
zadnjic = {}
kupec
for vrstica in open("zapisnik.txt"):
= vrstica.split(",")
kaj, kdo, koliko = int(koliko)
koliko if kaj not in prvic:
= koliko
prvic[kaj] = koliko
zadnjic[kaj] = kdo kupec[kaj]
Poglejmo, kako jih polnimo. V slovar prvic
bomo dodali
predmet, ki ga prvič vidimo. Preprosto preverimo, ali je že tam; če ga
ni, ga dodamo, če je, pa nič. V slovar zadnjic
zapišemo
ceno vsakega predmeta, ki ga vidimo. Ko to storimo zadnjič, bomo
zapisali zadnjo ceno. Podobno v slovar kupec
vpisujemo vse
ponudnike. Zadnji zapisani ponudnik je potem dejanski kupec. Preverimo,
ali so slovarji videti smiselno.
prvic
{'slika': 31,
'pozlačen dežnik': 29,
'Meldrumove vaze': 44,
'skodelice': 50,
'kip': 30,
'čajnik': 15,
'srebrn jedilni servis': 27,
'perzijska preproga': 16}
zadnjic
{'slika': 45,
'pozlačen dežnik': 29,
'Meldrumove vaze': 78,
'skodelice': 83,
'kip': 107,
'čajnik': 15,
'srebrn jedilni servis': 63,
'perzijska preproga': 21}
kupec
{'slika': 'Fanči',
'pozlačen dežnik': 'Ema',
'Meldrumove vaze': 'Cilka',
'skodelice': 'Berta',
'kip': 'Dani',
'čajnik': 'Berta',
'srebrn jedilni servis': 'Greta',
'perzijska preproga': 'Helga'}
Zdaj lahko seštejemo porabo po osebah. Da ne bo vedno
if
, bomo uporabili setdefault
. (Obstaja tudi
boljša reč, defaultdict
, vendar jo na predavanjih včasih
omenimo že tu, včasih kasneje).
= {}
poraba = {}
dvig for kaj, kdo in kupec.items():
0)
poraba.setdefault(kdo, += zadnjic[kaj]
poraba[kdo]
print()
print("Poraba po osebah:")
for oseba in poraba:
print(oseba, "-", poraba[oseba])
Poraba po osebah:
Fanči - 45
Ema - 29
Cilka - 78
Berta - 98
Dani - 107
Greta - 63
Helga - 21
Za konec pa se še sprehodimo po slovarjih z začetnimi in končnimi cenami ter izpišemo razlike.
for izdelek in prvic:
print(izdelek, "-", zadnjic[izdelek] - prvic[izdelek])
slika - 14
pozlačen dežnik - 0
Meldrumove vaze - 34
skodelice - 33
kip - 77
čajnik - 0
srebrn jedilni servis - 36
perzijska preproga - 5
Nepomemben estetski detajl: lahko bi pisali tudi
for izdelek, prva in prvic.items():
print(izdelek, "-", zadnjic[izdelek] - prva)
slika - 14
pozlačen dežnik - 0
Meldrumove vaze - 34
skodelice - 33
kip - 77
čajnik - 0
srebrn jedilni servis - 36
perzijska preproga - 5
Tako bi eno ceno dobili "zastonj" brez indeksiranja. To imamo vedno
radi, tu pa izjemoma nisem naredil tako, ker mi je všeč simetrija:
zadnjic[izdelek] - prvic[izdelek]
je lepše kot
zadnjic[izdelek] - prva
. Lepe, simetrične, urejene,
sistematične programe je lažje brati in vsebujejo manj napak.
Tretja možnost bi bila
for (izdelek, prva), zadnja in zip(prvic.items(), zadnjic.values()):
print(izdelek, "-", zadnja - prva)
slika - 14
pozlačen dežnik - 0
Meldrumove vaze - 34
skodelice - 33
kip - 77
čajnik - 0
srebrn jedilni servis - 36
perzijska preproga - 5
Vendar (a) tega še ne znamo, (b) je grozno in čudno in (c) predpostavlja, da bo vrednosti v obeh slovarjih zložene v enakem vrstnem redu, kar je čudna in nevarna predpostavka.