Napišite funkcijo knjigovodstvo(ime_datoteke), ki prejme
ime datoteke s prihodki (vrstice s pozitivnimi števili) in odhodki
(negativna števila) v obliki, kot jo kaže okvirček na desni. Funkcija
mora vrniti trojko: seznam s pari imen dohodkov in pripadajočih zneskov,
seznam s pari imen odhodkov in pripadajočih cen (kot pozitivna števila)
ter skupno vsoto. Za datoteko
slika: 50
slika: 100
tempera: -3
stol: -20
kip: 20
zrak: 0
torba: 12
vrne
([('slika', 50), ('slika', 100), ('kip', 20), ('torba', 12)],
[('tempera', 3), ('stol', 20)],
159)
pri čemer je 159 preprosto vsota vseh številk.
Najprej pripravimo, kar bomo vrnili - seznama prihodki
in odhodki ter bilanca.
Nato gremo po datoteki: vsako vrstico razdelimo glede na
: in pretvorimo znesek v število. Če je šteivlo negativno,
dodamo par s stvarjo in zneskom v odhodki (pri čemer mora
biti število -znesek), sicer v prihodki. Pa
bilanco povečamo za znesek.
def knjigovodstvo(ime_datoteke):
prihodki = []
odhodki = []
bilanca = 0
for vrstica in open(ime_datoteke):
stvar, znesek = vrstica.split(":")
znesek = int(znesek)
if znesek < 0:
odhodki.append((stvar, -znesek))
elif znesek > 0:
prihodki.append((stvar, znesek))
bilanca += znesek
return prihodki, odhodki, bilancaNekateri radi pišejo
if znesek > 0:
bilanca += znesek
else:
bilanca -= abs(znesek)
To seveda ni potrebno. Python zna prištevati negativne vrednosti. :)
Prav tako je lepo, da bilanco spreminjamo izven if in ne
znotraj, ločeno za odhodke in za prihodke.
Eden od študentov je poskusil nalogo rešiti z numpy-jem.
Sicer se mu ni čisto posrečilo, vendar gre in je kar lepo. Dobra
ideja.
def knjigovodstvo(ime_datoteke):
podatki = np.genfromtxt(ime_datoteke, delimiter=":", dtype=str)
stvari = podatki[:, 0]
cene = podatki[:, 1].astype(int)
prihodki = cene > 0
odhodki = cene < 0
return (list(zip(stvari[prihodki], cene[prihodki])),
list(zip(stvari[odhodki], -cene[odhodki])),
np.sum(cene))Zoprna stvar je tisto na koncu: z zip poberemo skupaj
stvari in cene, da nam sestavi pare, potem pa pokličemo še
list, da jih zložimo v seznam.
Napiši funkcijo draginja(odhodki), ki vrne seznam parov
imen stvari in cen. Ista stvar se lahko pojavi večkrat, a morda z
različnimi cenami. Funkcija mora vrniti ime stvari, katere povprečna
cena je bila največja. Če je takšnih stvari več, lahko vrne poljubno
izmed njih.
Klic
draginja([('stol', 20), ('torba', 12), ('tempera', 3), ('miza', 50), ('stol', 30), ('stol', 60), ('miza', 40), ('torba', 5)])
vrne 'miza', saj je povprečna cena miz enaka
(50 + 40) / 2 = 45, medtem ko je povprečna cena, recimo,
stolov (20 + 30 + 60) / 3 = 36,66, torbe in tempere pa so
še cenejše.
Tole je naloga iz slovarjev. Da bomo lahko računali povprečne cene, bomo potrebovali dva: v enem beležimo vsote cen vsake stvari, v drugem število takšnih stvari.
Ko se odločimo glede tega, je funkcija preprosta.
def draginja(odhodki):
skupna_cena = defaultdict(float)
skupno_kosov = defaultdict(int)
for stvar, cena in odhodki:
skupna_cena[stvar] += cena
skupno_kosov[stvar] += 1
naj_stvar, naj_povp = None, -1
for stvar in skupna_cena:
povp = skupna_cena[stvar] / skupno_kosov[stvar]
if povp > naj_povp:
naj_stvar, naj_povp = stvar, povp
return naj_stvarZoprni drugi del se da skrajšati, če znamo bolj spretno uporabljati
max in poznamo lambde.
def draginja(odhodki):
skupna_cena = defaultdict(float)
skupno_kosov = defaultdict(int)
for stvar, cena in odhodki:
skupna_cena[stvar] += cena
skupno_kosov[stvar] += 1
return max(skupna_cena, key=lambda stvar: skupna_cena[stvar] / skupno_kosov[stvar])Napišite funkcijo dragocenosti(stvari, cene, meja), ki
prejme numpy-jevo tabelo z imeni stvari in dvodimenzionalno tabelo,
katere vrstice ustrezajo stvarem (v enakem vrstnem redu kot so te
naštete v prvi tabeli), stolpci pa dnevom. Vrednosti v tabeli povedo,
koliko je stvar stala na posamezni dan.
Funkcija mora vrniti tabelo z imeni vseh stvari, katerih cene so bile vsaj en dan višje od podane meje meja. Vrstni red mora biti enak vrstnemu redu v tabeli stvari.
Pri tej nalogi pričakujemo rešitev v čistem numpy-ju, brez zank v Pythonu.
Takole.
def dragocenosti(stvari, cene_po_dnevih, meja):
return stvari[np.any(cene_po_dnevih > meja, axis=1)]Ali pa takole.
def dragocenosti(stvari, cene_po_dnevih, meja):
return stvari[np.max(cene_po_dnevih, axis=1) > meja]Ko poženete teste, se bo v direktoriju s programom pojavila datoteka knjigovodstvo.html. Lahko jo odprete v brskalniku ali urejevalniku.
Napišite funkcijo spletno_knjigovodstvo(ime_datoteke),
ki zna prebrati podatke iz takšne datoteke. Predpostaviti smete, da opis
nakupa vedno vsebuje le eno število ter da je to število pozitivno in
celo. Funkcija mora vrniti seznam s pari stvari in cen. Za podano
datoteko naj vrne
[('slika', 50), ('slika', 100), ('tempera', 3), ('polomljen stol', 20), ('kip', 20), ('zrak', 0), ('torba', 12)].
Seveda bomo uporabili BeautifulSoup in regularne
izraze.
Podatki so v delu HTML-ja, ki je videti tako:
<dt>slika</dt>
<dd>Stala je 50, lahko bi tudi malo manj.</dd>
<dt>slika</dt>
<dd>Ta je bila malo dražje, zanjo smo dali 100.</dd>
Poiščemo vse dt in potem dd, ki jim
sledijo. Znotraj tega, kar je bilo v dd poiščemo zaporedja
števk \d+. Kar najdemo, pretvorimo v število.
def spletno_knjigovodstvo(ime_datoteke):
soup = BeautifulSoup(open(ime_datoteke), "html.parser")
postavke = []
for vrstica in soup.find_all("dt"):
stvar = vrstica.text
opis = vrstica.find_next_sibling("dd").text
znesek = re.search(r"\d+", opis).group()
postavke.append((stvar, int(znesek)))
return postavkeNapišite funkcijo evidenca(postavke, ime_datoteke), ki
prejme postavke v obliki trojk z imenom stvarmi, ceno za kos in številom
kosov, na primer
[("slika", 50, 2), ("tempera", 3, 1), ("stol", 20, 1), ("kip", 20, 12), ("zrak", 0, 141), ("torba", 12, 1)].
Funkcija mora v datoteko ime_datoteke zapisati tabelo v obliki, ki jo
kaže slika na desni. Točno obliko - število presledkov - razberite iz
testov.
Stvar Cena x Kosov Skupaj
------------------------------------
slika 50 x 2 100
tempera 3 x 1 3
stol 20 x 1 20
kip 20 x 12 240
zrak 0 x 141 0
torba 12 x 1 12
Tule gre zgolj za osnovno oblikovanje nizo: prešteti moramo, na
koliko znakov poravnamo kakšno stvar, pa z > in
< potiskati stvari na desno in na levo.
def evidenca(postavke, ime_datoteke):
f = open(ime_datoteke, "w")
f.write(f"{'Stvar':10} {'Cena':>6} x {'Kosov':<5} {'Skupaj':>10}\n")
f.write("-" * 36 + "\n")
for stvar, cena, kosov in postavke:
f.write(f"{stvar:10} {cena:>6} x {kosov:<5} {cena * kosov:10}\n")