Naloge na Tomotu rešujete tako, da v datoteko (v prazen prostor za
komentarjem, ki vsebuje navodila) vpišete rešitev in pritisnete tipko
F5
. S tem se vaš program naloži v konzolo in zaženejo se testi, ki
preverijo pravilnost rešitve.
Naloge na Tomotu rešujete tako, da v datoteko (v prazen prostor za
komentarjem, ki vsebuje navodila) vpišete rešitev in pritisnete tipko
F5
. S tem se vaš program naloži v konzolo in zaženejo se testi, ki
preverijo pravilnost rešitve.
Vpišite poljubno celo število ter nalogo pošljite na Tomota.
192837465
Vpišite celo število, a ne kateregakoli. Če želite ugotoviti, katero je pravo, berite opozorila, ki jih sporoča Tomo.
314
Vpišite število, ki je uradna rešitev prve podnaloge.
Uradno rešitev lahko na Tomotu vidite šele takrat, ko podnalogo pravilno rešite. Uradno rešitev se vam vedno splača pogledati in jo primerjati s svojo rešitvijo.
192837465
Petvrstično smrečico lahko v Pythonu izpišemo z naslednjim programom:
print("*")
print("**")
print("***")
print("****")
print("*****")
Sestavite program, ki izpiše osemvrstično smrečico.
print("*") print("**") print("***") print("****") print("*****") print("******") print("*******") print("********")
Program za izpis osemvrstične smrečice popravite tako, da namesto niza
z '**...*'
uporabite izraz n * '*'
, na primer namesto
niza '*****'
uporabite izraz 5 * '*'
.
print(1 * "*") print(2 * "*") print(3 * "*") print(4 * "*") print(5 * "*") print(6 * "*") print(7 * "*") print(8 * "*")
Osemvrstično smrečico izpišite z enim samim klicem funkcije print
.
Namig: znak za prelom vrstice je "\n"
.
print(1 * znak + "\n" + 2 * znak + "\n" + 3 * znak + "\n" + 4 * znak + "\n" + 5 * znak + "\n" + 6 * znak + "\n" + 7 * znak + "\n" + 8 * znak)
Osemvrstično smrečico izpišite še desno poravnano. Petvrstična desno poravnana smrečica izgleda takole:
*
**
***
****
*****
Namig: na začetku vsake vrstice izpišite ustrezno število presledkov.
znak = "*" print(7 * " " + 1 * znak + "\n" + 6 * " " + 2 * znak + "\n" + 5 * " " + 3 * znak + "\n" + 4 * " " + 4 * znak + "\n" + 3 * " " + 5 * znak + "\n" + 2 * " " + 6 * znak + "\n" + 1 * " " + 7 * znak + "\n" + 8 * znak)
Osemvrstično smrečico izpišite še sredinsko poravnano in z razmaki. Petvrstična sredinsko poravnana smrečica z razmaki izgleda takole:
*
* *
* * *
* * * *
* * * * *
Namig: levi rob je enak kot pri desno poravnani smrečici, za vsakim osnovnim znakom pa je presledek.
znakp = "* " print(7 * " " + 1 * znakp + "\n" + 6 * " " + 2 * znakp + "\n" + 5 * " " + 3 * znakp + "\n" + 4 * " " + 4 * znakp + "\n" + 3 * " " + 5 * znakp + "\n" + 2 * " " + 6 * znakp + "\n" + 1 * " " + 7 * znakp + "\n" + 8 * znakp)
Izpišite poln kvadrat, sestavljen iz znaka "+"
.
Velikost kvadrata naj bo shranjena v spremenljivki n
.
Na primer, če je n = 4
, se naj izpiše
++++
++++
++++
++++
Kvadrat naj bo velikosti vsaj
n = 7 vrstica = n * '+' + '\n' kvadrat = n * vrstica print(kvadrat)
Izpišite še prazen kvadrat, obrobljen z znakom "+"
.
Velikost kvadrata naj bo shranjena v spremenljivki n
.
Na primer, če je n = 4
, se naj izpiše
++++
+ +
+ +
++++
Kvadrat naj bo velikosti vsaj
n = 7 polna = n * '+' + '\n' prazna = '+' + (n - 2) * ' ' + '+' + '\n' kvadrat = polna + (n - 2) * prazna + polna print(kvadrat)
Napišite program, ki izpiše šahovsko desko razsežnosti "@"
, bela polja pa iz znakov
"."
. Velikost polj naj bo shranjena v spremenljivki m
. Tudi
spremenljivka n
mora biti podana.
Na primer, če je m = 2
in n = 3
, naj se izpiše:
@@..@@..@@..
@@..@@..@@..
..@@..@@..@@
..@@..@@..@@
@@..@@..@@..
@@..@@..@@..
..@@..@@..@@
..@@..@@..@@
@@..@@..@@..
@@..@@..@@..
..@@..@@..@@
..@@..@@..@@
m = 2 n = 3 vzorec1 = ((m * '@' + m * '.') * n + '\n') * m vzorec2 = ((m * '.' + m * '@') * n + '\n') * m kvadrat = (vzorec1 + vzorec2) * n print(kvadrat)
Napišite program, ki izpiše šahovsko desko razsežnosti
####
####
####
####
bela pa oblike
++++
+ +
+ +
++++
Velikost polj naj bo shranjena v spremenljivki m
. Tudi spremenljivka
n
mora biti podana.
Na primer, če je m=3
in n=2
, naj se izpiše:
###+++###+++
###+ +###+ +
###+++###+++
+++###+++###
+ +###+ +###
+++###+++###
###+++###+++
###+ +###+ +
###+++###+++
+++###+++###
+ +###+ +###
+++###+++###
m=3 n=2 crna = m * '#' bela = m * '+' prazna = '+' + (m - 2) * ' ' + '+' vzorec1 = ((crna + bela) * n + '\n' + ((crna + prazna) * n + '\n') * (m-2) + (crna + bela) * n + '\n') vzorec2 = ((bela + crna) * n + '\n' + ((prazna + crna) * n + '\n') * (m-2) + (bela + crna) * n + '\n') kvadrat = (vzorec1 + vzorec2) * n print(kvadrat)
Program vpraša za dve števili in za njun produkt, ter izpiše uporabnikove odgovore in pravi produkt. Vendar ne dela!
ime = input("Kako ti je ime? ")
print("Pozdravljen, ', ime, 'bi vadil poštevanko? ")
int(input("Pa dajva. Vpiši prvi faktor: "))
int(input("Pa še drugi faktor: "))
rezultat = a*b
c = input("Koliko, misliš, znaša produkt? ")
print("Napisal si, da je", a, "krat", b, "enako", c)
print("Pravilen odgovor je", rezulat)
Skopiraj ga, poskusi prevesti in popravi!
ime = input("Kako ti je ime? ") print("Pozdravljen,", ime, "bi vadil poštevanko? ") a = int(input("Pa dajva. Vpiši prvi faktor: ")) b = int(input("Pa še drugi faktor: ")) rezultat = a * b c = input("Koliko, misliš, znaša produkt? ") print("Napisal si, da je", a, "krat", b, "enako", c) print("Pravilen odgovor je", rezultat)
Ko sem bil jaz bruc (ja, v prazgodovini ;-) ) smo računalniške programe pisali na kartice. Na vsaki kartici je bil en stavek. In ni bilo tako redko, da si se spotaknil, razsul šop kartic in ... Potem je bilo potrebno zadevo ustrezno urediti. In sedaj imamo podoben problem. Virus je v naši datoteki premešal vrstice.
#preberemo podatke
print ('Program ti bo spremenil sekunde v dneve, ure, minute in sekunde')
print (sekZacasne,'sekund je natanko')
print (dnevi, 'dni,', ure, 'ur,', minute, 'minut in', sekunde,'sekund')
minZacasne = sekZacasne // 60 #celi del deljenja so vse minute
minute = minZacasne % 60 #ostanek od deljenja z 60 so minute ostalo že ure
sekunde = sekZacasne % 60 #ostanek od deljenja z 60 so sekunde
ure = ureZacasne % 24 #ostanek od deljenja z 24 so ure ostalo dnevi
ureZacasne = minZacasne // 60 #celi del od deljenja z 60 so vse ure
dnevi = ureZacasne // 24 #celi del deljenja z 24 so dnevi
sekZacasne = int(input('Vnesi sekunde: '))
#izpišemo rezultat
Uredi jih tako, da bo program smiselno deloval!
#preberemo podatke print ('Program ti bo spremenil sekunde v dneve, ure, minute in sekunde') sekZacasne = int(input('Vnesi sekunde: ')) sekunde = sekZacasne % 60 #ostanek od deljenja z 60 so sekunde minZacasne = sekZacasne // 60 #celi del deljenja so vse minute minute = minZacasne % 60 #ostanek od deljenja z 60 so minute ostalo že ure ureZacasne = minZacasne // 60 #celi del od deljenja z 60 so vse ure ure = ureZacasne % 24 #ostanek od deljenja z 24 so ure ostalo dnevi dnevi = ureZacasne // 24 #celi del deljenja z 24 so dnevi #izpišemo rezultat print (sekZacasne,'sekund je natanko') print (dnevi, 'dni,', ure, 'ur,', minute, 'minut in', sekunde,'sekund')
Hišnik mora vsak mesec očistiti bazen. Da ga lahko očisti, mora najprej iz njega izčrpati vodo. Ker je bolj lene sorte, pa bi med iztakanjem vode (ki traja kar nekaj časa) raje odšel v bližnjo kavarno na pogovor s prijateljem, namesto da bi stražil bazen. Tukaj je program, ki bo za bazen velikosti 2 m x 3m x 9m izračunal, koliko sekund se bo praznil bazen, če vsako sekundo izteče iz bazena 23l vode. Če ste že pozabili: kubični decimeter vode = 1l vode.
#Vnos dimenzij bazena.
globina = 2
širina = 3
dolžina = 9
# Pretvorba dimenzij bazena v dm.
dolžinaVdm = dolžina * 10
širinaVdm = širina * 10
globinaVdm = globina * 10
# Izračun prostornine bazena v kubičnih dm.
prostorninaVdm = dolžinaVdm * širinaVdm * globinaVdm
# Vnos pretoka vode v sekundi.
prostorninaIztekaV1sek = 23
# Izračun časa praznjenja bazena.
časPraznjenjaVsek = prostorninaVdm / prostorninaIztekaV1sek
# Izpis rezultata.
print('Bazen velikosti', dolžina, 'm ×', širina, 'm ×', globina, 'm', 'se bo praznil', časPraznjenjaVsek, 'sekund.')
Spremeni zgornji program tako, da boš dimenzije bazena in hitrost iztekanja prebral! Dimenzije so v celih metrih!
#Vnos dimenzij bazena. globina = int(input('Vnesi globino bazena ')) širina = int(input('Vnesi širino bazena ')) dolžina = int(input('Vnesi dolžino bazena ')) # Pretvorba dimenzij bazena v dm. dolžinaVdm = dolžina * 10 širinaVdm = širina * 10 globinaVdm = globina * 10 # Izračun prostornine bazena v kubičnih dm. prostorninaVdm = dolžinaVdm * širinaVdm * globinaVdm # Vnos pretoka vode v sekundi. prostorninaIztekaV1sek = int(input('Koliko l vode v sekundi izteče: ')) # Izračun časa praznjenja bazena. časPraznjenjaVsek = prostorninaVdm / prostorninaIztekaV1sek # Izpis rezultata. print('Bazen velikosti', dolžina, 'm ×', širina, 'm ×', globina, 'm', 'se bo praznil', časPraznjenjaVsek, 'sekund.')
Hišnik je zamenjal službo. A tudi tam imajo bazen in hišnik ga mora spet čistiti.
Že je ves vesel zagnal tvoj program, a kaj, ko je pri merjenju ugotovil, da
je globina bazena 2.34m.
Pomagaj mu in program popravi tako, da bo sedaj sprejel podatke v obliki decimalnih števil.
Potrudi se in rezultate izpiši lepo. Namig: oglej si, kaj počne float(12.45)
in print("%.2f" % 1.2399)
ali pa print("{:.2f}".format(3.1415926))
,
oziroma na spletu poišči "float Python 3"
in "format string Python 3"
#Vnos dimenzij bazena. globina = float(input('Vnesi globino bazena ')) širina = float(input('Vnesi širino bazena ')) dolžina = float(input('Vnesi dolžino bazena ')) # Pretvorba dimenzij bazena v dm. dolžinaVdm = dolžina * 10 širinaVdm = širina * 10 globinaVdm = globina * 10 # Izračun prostornine bazena v kubičnih dm. prostorninaVdm = dolžinaVdm * širinaVdm * globinaVdm # Vnos pretoka vode v sekundi. prostorninaIztekaV1sek = float(input('Koliko l vode v sekundi izteče: ')) # Izračun časa praznjenja bazena. časPraznjenjaVsek = prostorninaVdm / prostorninaIztekaV1sek # Izpis rezultata. print('Bazen velikosti', "{:.2f}".format(dolžina), 'm ×', "{:.2f}".format(širina), 'm ×', "{:.2f}".format(globina), 'm', 'se bo praznil', "{:.2f}".format(časPraznjenjaVsek), 'sekund.')
Hišnik je z našim programom sicer zelo zadovoljen, a zadnjič se je v pretvarjanju sekund
v minute uštel in je zato prišel nazaj h bazenu cele pol ure prezgodaj.
Zato prosi, če mu namesto časa v sekundah izpišeš čas v urah, minutah in sekundah.
Tukaj boste morali sekunde iz decimalne oblike pretvoriti v celo število. Ugotovi,
kako to storimo v Pythonu. Namig: https://docs.python.org/3/library/functions.html
#Vnos dimenzij bazena. globina = float(input('Vnesi globino bazena ')) širina = float(input('Vnesi širino bazena ')) dolžina = float(input('Vnesi dolžino bazena ')) # Pretvorba dimenzij bazena v dm. dolžinaVdm = dolžina * 10 širinaVdm = širina * 10 globinaVdm = globina * 10 # Izračun prostornine bazena v kubičnih dm. prostorninaVdm = dolžinaVdm * širinaVdm * globinaVdm # Vnos pretoka vode v sekundi. prostorninaIztekaV1sek = float(input('Koliko l vode v sekundi izteče: ')) # Izračun časa praznjenja bazena. časSek = round(prostorninaVdm / prostorninaIztekaV1sek) časMinut = časSek // 60 časSek = časSek % 60 časUr = časMinut // 60 časMinut = časMinut % 60 # Izpis rezultata. print('Bazen velikosti', "{:.2f}".format(dolžina), 'm ×', "{:.2f}".format(širina), 'm ×', "{:.2f}".format(globina), 'm', 'se bo praznil', časUr, "ur,", časMinut, "minut in", časSek, "sekund.")
Naslednji program naj bi seštel dva kota, podana v stopinjah, minutah in sekundah
print('Prvi kot\n=========')
stopinje1 = int(input('stopinje: '))
minute1 = int(input('minute: '))
sekunde1 = int(input('sekunde: '))
print('Drugi kot\n=========')
stopinje2 = int(input('stopinje: '))
minute2 = int(input('minute: '))
sekunde2 = int(input('sekunde: '))
stopinje = stopinje1 + stopinje2
minute = minute1 + minute2
sekunde = sekunde1 + sekunde2
minute = minute + sekunde // 60
minute = minute % 60
print('Vsota kotov je', stopinje, 'stopinj,', minute, 'minut in', sekunde, 'sekund.')
Žal ne dela pravilno. Popravi ga!
print('Prvi kot\n=========') stopinje1 = int(input('stopinje: ')) minute1 = int(input('minute: ')) sekunde1 = int(input('sekunde: ')) print('Drugi kot\n=========') stopinje2 = int(input('stopinje: ')) minute2 = int(input('minute: ')) sekunde2 = int(input('sekunde: ')) stopinje = stopinje1 + stopinje2 minute = minute1 + minute2 sekunde = sekunde1 + sekunde2 minute = minute + sekunde // 60 sekunde = sekunde % 60 stopinje = stopinje + minute // 60 minute = minute % 60 print('Vsota kotov je', stopinje, 'stopinj,', minute, 'minut in', sekunde, 'sekund.')
Spodaj je napisan program, ki kot v radianih (realno število) pretvori in izpiše v stopinjah in minutah (kot celi števili; za minute naj program ne uporabi zaokroženja ampak naj samo odreže decimalna mesta).
Primer: Za
kot = 2.185
naj program izpiše
2.185 radianov je 125 stopinj in 11 minut.
Žal ne deluje povsem pravilno. Popravi ga!
import math # Število π je shranjeno v math.pi
kot = input('Kot: ')
stopinje = kot * 360 / math.pi
minute = 60 * stopinje
stopinje = int(stopinje)
print('{:.6}'.format(kot), 'radianov je', stopinje, 'stopinj in', minute, 'minut
import math # Število π je shranjeno v math.pi kot = float(input('Vnesi kot: ')) stopinje = kot * 360 / (2 * math.pi) minute = int(60 * (stopinje - int(stopinje))) stopinje = int(stopinje) print('{:.6}'.format(kot), 'radianov je', stopinje, 'stopinj in', minute, 'minut.')
Program
ura = int(input('Ur: '))
minuta = int(input('Minut: '))
alfa = 60 * (3 * minuta) # Kot minutnega kazalca v kotnih minutah.
beta = 60 * (ura + minuta) # Kot urnega kazalca v kotnih minutah.
minute = abs(alfa - beta)
minute = min(minute, 360 * 60 - minute) # Vzamemo manjšega od obeh kotov.
minute = minute - int(minute) # Odrežemo decimalni del.
stopinje = minute // 60
print('Kot med urnim in minutnim kazalcem je', stopinje, 'stopinj in', minute, 'minut.')
naj bi izračunal manjšega izmed kotov med urnim in
minutnim kazalcem ob danem času. Čas je podan z uro in minutami.
Upoštevajte, da se vsako minuto tudi urni kazalec malo prestavi.
Trenutno uro in minuto imate podano v spremenljivkah z imenoma ura
in minuta
. Kot naj bo izpisan v obliki
Kot med urnim in minutnim kazalcem je x stopinj in y minut.
kjer sta x
in y
celi števili (minut ne zaokrožuj, ampak samo odreži
decimalni del).
Primer: za vrednosti
ura = 17
minuta = 47
naj program izpiše
Kot med urnim in minutnim kazalcem je 108 stopinj in 30 minut.
ura = int(input('Ur: ')) minuta = int(input('Minut: ')) ura = ura % 12 alfa = 60 * (6 * minuta) # Kot minutnega kazalca v kotnih minutah. beta = 60 * (30 * ura + 0.5 * minuta) # Kot urnega kazalca v kotnih minutah. minute = abs(alfa - beta) minute = min(minute, 360 * 60 - minute) # Vzamemo manjšega od obeh kotov. minute = int(minute) # Odrežemo decimalni del. stopinje = minute // 60 minute = minute % 60 print('Kot med urnim in minutnim kazalcem je', stopinje, 'stopinj in', minute, 'minut.')
Tu je sklop osnovnih nalog za spoznavanje funkcij v Pythonu
Sestavite funkciji, ki vrneta zahtevani sredini dveh števil.
Zapišite funkcijo aritmeticna(a, b)
, ki za števili
def aritmeticna (a, b): '''Funkcija vrne aritmetično sredino števil a in b.''' return (a + b)/2
Zapišite funkcijo geometricna(a, b)
, ki za števili
Namig - oglej si dokumentacijo in zgled
import math # da bomo lahko uporabili vgrajeno funkcijo za korenjenje def geometricna (a, b): '''Funkcija vrne geometrično sredino števil a in b.''' return math.sqrt(a*b)
Dano imamo decimalno število. Sestavite funkcijo desetinke(x)
, ki vrne
desetinke števila x
.
Na primer:
>>> desetinke(3.7)
7
>>> desetinke(6.127)
1
def desetinke(x): '''vrne desetinke števila x''' stevilo = 10 * abs(x) # premik decimalne pike v desno. Da ne bo kaj čudnega, delamo z abs celiDel = int(stevilo) deset = celiDel % 10 # desetinke so enice novega števila return deset
Dano imamo decimalno število. Funkcija celiDecimalni(x)
naj bi vrnila
celi in prvi dve decimalki števila x
tako, kot kažejo primeri
Na primer:
>>> celiDecimalni(3.7)
(3, 70)
>>> celiDecimalni(-6.127)
(-6, 12)
>>> celiDecimalni(12.0127)
(12, 1)
A funkcija
def celiDecimalni(x):
'''vrne celi in decimalni del števila x'''
celiDel = int(x)
decimalni = 100 * (x - celiDel)
return celiDel, decimalniDel
ne dela vedno tako. Poišči in odpravi napake!
def celiDecimalni(x): '''vrne celi in decimalni del števila x''' celiDel = int(x) x = abs(x) decimalniDel = int((x - abs(celiDel))*100) return celiDel, decimalniDel
V posodo, katere dno ima obliko kvadrata, nalijemo vodo vse do roba.
Če vanjo vržemo kroglo z radijem 5cm, nam funkcija
import math
def kolikoOstalo(širina, višina):
'''Na tri decimalke natančno vrne, koliko litrov vode je ostalo v posodi'''
volumenKrogle = 4/ 3 * math.pi * 0.125
volumenPosode = širina ** 2 * višina / 1000
ostanekVode = round(volumenPosode - volumenKrogle, 3)
return ostanekVode
vrne, koliko litrov vode ostane v posodi (vse mere so podane v cm). Spremeni to funkcijo v kolikoOstalo(širina, višina, polmer)
,
ki izračuna koliko litrov vode je ostalo v posodi, če vanjo damo kroglo s polmerom polmer
.
import math def kolikoOstalo(širina, višina, polmer): '''Na tri decimalke natančno vrne, koliko litrov vode je ostalo v posodi''' volumenKrogle = 4/ 3 * math.pi * (polmer / 10)**3 volumenPosode = širina ** 2 * višina / 1000 ostanekVode = round(volumenPosode - volumenKrogle, 3) return ostanekVode
V posodo sedaj položimo stožec, katerega premer je enak širini posode, višina
pa enaka globini posode.
Napišite funkcijo kolikoOstaloSt(širina, višina, n)
, ki izračuna koliko litrov
vode je ostalo v posodi ter vrne rezultat, zaokrožen na n decimalk.
Funkcija sprejme širino in višino posode v cm.
import math def kolikoOstaloSt(širina, višina, n): '''Na n decimalk natančno vrne, koliko litrov vode je ostalo v posodi''' volumenStozca = 1 / 3 * math.pi * (širina / 2) ** 2 * višina / 1000 volumenPosode = širina ** 2 * višina / 1000 ostanekVode = round(volumenPosode - volumenStozca, n) return ostanekVode
Radi bi sestavili niz, ki ga sestavlja n enakih znakov. Zato sestavi funkcijo
kopija
, ki vrne niz, ki ga sestavlja n kopij znaka.
Če torej napišemo program:
print(kopija('X', 5))
črta = kopija('-', 3)
print(črta + " : " + str(len(črta)))
bo izpis:
XXXXX
--- : 3
def kopija(znak, n): '''Vrne niz, ki ga sestavlja n kopij znaka n''' niz = znak * n return niz
Sestavi funkcijo črkaH(n, znak)
, ki za podatek n izpiše na zaslon veliko
črko H, visoko 2n + 1 znakov in široko n + 2 znakov.
Primer:
>>>črkaH(2, 'o')
o o
o o
oooo
o o
o o
def črkaH(n, znak): '''Izpišimo črko H''' # zgornji del vrstica = znak + ' ' * n + znak + '\n' print(n * vrstica, end = '') # na koncu smo že skočili v novo vrsto # srednji del print(znak * (n + 2)) # spodnji del vrstica = znak + ' ' * n + znak + '\n' print(n * vrstica, end = '') # na koncu smo že skočili v novo vrsto
Pri varčevanju na obroke na začetku vplačamo nek znesek, nato pa vsak mesec doplačujemo mesečne obroke. Zaradi enostavnosti predpostavimo, da so vplačila vedno prvi dan v mesecu, vrednost varčevalnega računa pa se vedno računa ob koncu meseca. Denar, ki ga imamo na varčevalnem računu, se obrestuje po fiksni obrestni meri.
V bančništvu pogosto navajamo letno obrestno mero, obrestujemo pa mesečno. Zato je pred računanjem potrebno obrestno mero primerno spremeniti.
Napišite funkcijo mesecna_obrestna_mera(letna_obrestna_mera)
, ki kot
parameter sprejme letno obrestno mero v odstotkih, vrne pa ustrezno
mesečno obrestno mero kot decimalno število
(torej letni obrestni meri 12% ustreza mesečna obrestna mera 0.01).
def mesecna_obrestna_mera(r): '''Letna obrestna mera v obliki mesečne decimalne oblike.''' return r / 1200
Pri enostavnem obrestovanju s fiksno letno obrestno mero
Sestavite funkcijo
enostavno_obrestovanje(polog, letna_obrestna_mera, st_mesecev)
,
ki za enostavno obrestovanju izračuna vrednost denarja na računu pri danem
začetnem pologu, letni obrestni meri in številu mesecev.
Primeri:
>>> enostavno_obrestovanje(100, 10, 0)
100.0
>>> enostavno_obrestovanje(100, 12, 1)
101.0
>>> enostavno_obrestovanje(100, 10, 12)
110
def enostavno_obrestovanje(polog, letna_obrestna_mera, st_mesecev): '''Vrednost obrestovanega denarja pri enostavnem obrestovanju.''' return polog * (1 + mesecna_obrestna_mera(letna_obrestna_mera) * st_mesecev)
Pri obrestno obrestnem računu s fiksno letno obrestno mero
Sestavite funkcijo
obrestno_obrestovanje(polog, letna_obrestna_mera, st_mesecev)
,
ki izračuna vrednost denarja na računu pri danem začetnem pologu, letni
obrestni meri in številu mesecev, pri čemer se obresti računajo po obrestno
obrestnem računu.
Primeri:
>>> obrestno_obrestovanje(100, 10, 0)
100.0
>>> obrestno_obrestovanje(100, 10, 1)
100.83333333333333
>>> obrestno_obrestovanje(100, 12, 12)
112.68250301319698
def obrestno_obrestovanje(polog, letna_obrestna_mera, st_mesecev): '''Vrednost obrestovanega denarja pri obrestno obrestnem obrestovanju.''' return polog * (1 + mesecna_obrestna_mera(letna_obrestna_mera)) ** st_mesecev
Za uvod si najprej preberite nekaj o stripu Alan Ford (in še nekaj).
Lakota
Broj 1 je z zaskrbljenostjo potresel škatlo. Le nekaj fižolovih zrn je še ostalo. Spet lakota v Cvetličarni. Začel je deliti - eno zrno za Alana, eno za Jeremijo, eno zanj, eno za Grunfa. In spet eno zrno za Alana, eno za Jeremijo, eno zanj, eno za Grunfa in ... Ko so mu ostala manj kot 4 zrna, je zavzdihnil in vsa pospravil na svoj kupček. Že je želel poklicati k večerji, ko je v kotu zastokal Jeremija in se prebudi. Ah, tudi on mora dobiti svoj delež. Zrna na kup in eno za Alana, eno za Grunfa, ... Seveda, ko je bilo manj kot pet zrn, gredo spet vsa na kupček Broja 1. In ko je bil že skoraj pri koncu, se od nekje pojavita Oliver in Bob Rock. In spet od začetka ...
Da bo šlo hitreje, sestavi funkcijo zrna(fižoli, številoOseb)
, ki za dano število zrn in oseb vrne
koliko zrn dobijo člani skupine TNT in koliko Broj 1. Npr.
>>>zrna(72, 5)
14, 16
def zrna(koliko, osebe): '''Koliko zrn dobi osebe oseb, če vsi dobijo v načelu enako, morebiten preostanek pa pripade dodatno eni osebi''' večina = koliko // osebe en = koliko - večina * (osebe - 1) return večina, en
sir Oliver, izposojena ura in jašek
Na sprehodu sir Oliver čisto slučajno zavije v zlatarno in čez nekaj trenutkov
je že zunaj, s kričečim prodajalcem za sabo. Par hitrih zavojev in ko že kaže, da je
sir Oliver ušel, se znajde v slepi ulici. Gentleman kot sir Oliver definitivno je, si
ne bo dovolil, da bi ga zasačili z uro, ki si jo je sposodil, zato jo hitro odvrže v navpični jašek
na dnu katerega je malo vode. Skrbno posluša in čez nekaj časa zasliši čof.
Pomagaj mu in napiši funkcijo globinaJaška(čas)
, ki za podatek koliko časa je minilo od trenutka, ko
je sir Oliver spustil uro, do trenutka, ko je reklo čof, vrne na tri decimalke natančno globino jaška v metrih. Če ne poznaš enačb,
si pomagaj z wikipedijo. Za gravitacijski pospešek vzemi 9.81 m/s.
Namig: Python pozna funkcijo round(x, n)
. Kaj pa dela, ugotovi v dokumentaciji
ali pa bo dovolj, da pogledaš naslednjo nalogo.
def globinaJaška(t): '''Kako globok jke jašek, če premet pada t sekund''' g = 9.81 globina = 0.5 * g * t**2 rez = round(globina, 3) return rez
Grunf topničar
Grunf strelja s topom na domovanje Superhika, a ga nikakor ne more zadeti.
Tukaj je funkcija, ki izračuna maksimalno višino leta krogle,
import math
def maxViš(v, kot):
'''Maks. višina pri poševnem metu'''
kotRad = kot * math.pi / 180
najV = v**2 * math.sin(kotRad)**2
g = 10.0
zaokr = round(najV / (2*g), 1)
return zaokr
a kaj ko potrebuje domet!
Pomagaj mu in sestavi funkcijo domet(v, kot)
, ki na eno decimalko natančno
izračuna domet krogle, če s hitrostjo v
ustrelimo pod kotom kot
stopinj. Če si pozabil, gre za poševni met
Za g vzemi kar 10 m/s^2, zračni upor pa zanemari.
>>> domet(10, 45)
10.0
>>> domet(10, 60)
8.7
import math def domet(v, kot): '''Domet pri poševnem metu''' kotRad = kot * math.pi / 180 dom = v*v*math.sin(2*kotRad) g = 10.0 zaokr = round(dom / g, 1) return zaokr
Za uvod si preberite nekaj o Mirku in Slavku:
Prevara s čekom
Kurirji so iznajdljivi. Seveda Mirko in Slavko pa sploh. V roke sta dobila ček, kjer banka prinositelju izplača vrednos na njem napisanega tromestnega zneseka. Ampak Mirko ne bi bil Mirko, če ne bi kaj hitro ugotovil, da z malo spretnosti in ostrim nožičem lahko ček neopazno spremeni tako, da premeša števke na znesku. A kaj, ko je Mirko bolj slab v matematiki, rad pa bi ček popravil tako, da bo dobil kar se da veliko. Potoži se Slavku. Ah, to pa ja ni problem. Poglej to funkcijo. Malo jo spremeni, pa boš dobil največje možno število. Mirko sedaj proučuje
def kajDelam(n):
'''Pozor, n je obvezno tromestno naravno število
Spremenljivke imajo namenoma čudna imena.
'''
a = n - n % 10
b = a // 10 % 10
c = n - a
d = n // 100
e = max(b, c, d)
f = min(b, c, d)
g = b + c + d - e - f
return f, g, e
Premisli kaj funkcija počne in na osnovi ideje v njej namesto Mirka sestavi funkcijo najTromestno
, ki iz
danega tromestnega števila sestavi največje možno tromestno število
>>> najTromestno(137)
731
>>> najTromestno(625)
652
def najTromestno(n): '''Iz števk danega tromestnega števila naredi največje možno število''' enice = n % 10 desetice = n // 10 % 10 stotice = n // 100 najmanjše = min(enice, desetice, stotice) največje = max(enice, desetice, stotice) srednje = enice + desetice + stotice - najmanjše - največje # srednje po velikosti število = največje * 100 + srednje * 10 + najmanjše return število
Mirko, pazi metak!
Verjetno najbolj znamenit dialog med Mirkom in Slavkom je:
Kako hitro se mora Mirko skloniti, če Slavko strel opazi n
metrov proč
Sestavi funkcijo skloniSe(kolikoM, hitrostMetka)
, ki pove, v koliko sekundah, desetinkah
in stotinkah se mora Mirko skloniti, če Slavko opazi metek kolikoM
metrov proč in ima hitrost
hitrostMeta
m/s. Pazi, da bodo stotinke ustrezno zaokrožene!
def skloniSe(kolikoM, hitrostMetka): '''V koliko sekundah, destinkah in stotinkah se mora Mirko skloniti, če Slavko opazi metek `kolikoM` metrov proč in ima hitrost `hitrostMeta` m/s.''' čas = kolikoM/hitrostMetka časStotink = int(čas * 100 + 0.5) # če prištejemo 0.5, bomo prav zaokrožili stotink = časStotink % 10 desetink = (časStotink // 10) % 10 sekund = časStotink // 100 return (sekund, desetink, stotink)
Metak mrzkega neprijatelja
Slavka skrbi, če bo tudi on dovolj hiter, da bo ubežal krogli. Zato mu sestavi program, ki bo meril njegov rekacijski čas.
Če na začetek programa napišemo
import time
bomo, med drugim, dobili funkcijo time
, ki s klicem time.time()
vrne čas v sekundah od nekega trenutka v davni preteklosti.
Napiši program, ki bo izpisal Slavko, pazi metak! in izmeril, koliko časa je trajalo, da je Slavko pritisnil na tipko
Enter in potem izpisal, koliko sekund je Slavko potreboval za pritisk na tipko.
Namig: če veš, koliko je bila ura pred klicem funkcije input in koliko je bila ura po klicu,
znaš izračunati, koliko časa je minilo vmes.
>>>Slavko, pazi metak!
Slavko je reagiral v 2.503019332885742 s.
import time začetek = time.time() input('Slavko, pazi metak!') konec = time.time() print('Slavko je reagiral v', konec - začetek, 's.') print('\n')
Mirko in Slavko ob pomoči Dimnjačara pečeta palačinke
Mirko in Slavko sta v uspešni akciji zaplenila velike količine moke in jajc. Zato bosta za celo vas Glavuša na Kozari napekla palačinke.
Ampak kaj, ko ne vesta koliko. Dimnjačar jima je zato napisal funkcijo A kaj, ko mu je tik preden je odšel, izpod listov trpotca, ki jih je imel na čelu namesto obveze padlo par kapelj krvi in je sedaj funkcija
def kolikoPalačink(steviloOdraslih, steviloOtrok):
'''Vrne število paslačink potrebnih, da nasiti vse povabljene'''
PACKA
PACKA
palacinkeOdrasli = steviloOdraslih * odrasel
palacinkeOtroci = steviloOtrok * otrok
palacinkeSkupaj = palacinkeOdrasli + palacinkeOtroci + PACKA # še malo za rezervo
return palacinkeSkupaj
Na srečo pa so ostali še trije izpisi, ko jima je pokazal delovanje funkcije. Pomagaj Mirku in Slavku in dopolni funkcijo, da se bo obnašala kot prej, če so izpisi
Koliko je odraslih: 12
Koliko otrok: 5
Napeči je potrebno 77 palačink.
Koliko je odraslih: 21
Koliko otrok: 14
Napeči je potrebno 140 palačink.
Koliko je odraslih: 10
Koliko otrok: 15
Napeči je potrebno 87 palačink.
def kolikoPalačink(steviloOdraslih, steviloOtrok): '''Vrne število paslačink potrebnih, da nasiti vse povabljene''' odrasel = 5 otrok = 2 palacinkeOdrasli = steviloOdraslih * odrasel palacinkeOtroci = steviloOtrok * otrok palacinkeSkupaj = palacinkeOdrasli + palacinkeOtroci + 7 # še malo za rezervo return palacinkeSkupaj
Slavko peče torte
Po velikem uspehu s peko palačink, se je Slavko spravil peči torte. Po receptu za torto potrebujemo 0.8 kg margarine, 2 kg moke in 1.5 kg sladkorja. Sedaj Slavka zanima, kakšno je, glede na količine sestavin, ki jih ima na razpolago, največje možno število tort, ki jih lahko naredi.
Namig: Funkcija min
vrne najmanjšega izmed svojih parametrov.
Primer: Če imamo 5kg margarine, 7kg moke in 3.5kg sladkorja, lahko spečemo dve torti.
Slavku sestavi funkcijo kolikoTort(margarina, moka, sladkor)
, ki glede na dani recept
določi največje možno število tort.
def kolikoTort(margarina, moka, sladkor): '''Koliko lahko največ spečemo tort''' receptMargarina = 0.8 # količina margarine po receptu receptMoka = 2 # količina moke za eno torto po receptu receptSladkor = 1.5 # količina sladkorja po receptu # koliko tort glede na posamezno sestavimo izMoke = int(moka/receptMoka) izMargarine = int(margarina/receptMargarina) izSladkorja = int(sladkor/receptSladkor) možnoTort = min(izMoke, izMargarine, izSladkorja) return možnoTort
Mirko in smučarski skoki
Medtem, ko Slavko peče torte, je Mirko organiziral tekmovanje v smučarskih skokih.
Pri smučarskih skokih so točke skoka vsota:
Vsak od petih sodnikov lahko skakalcu dodeli največ 20 točk, ki so odvisne od položaj smuči med letom, ravnotežja med letom, položaja telesa, pristanka ipd. Točke sloga so vsota točk posamičnih sodnikov, pri čemer se najboljša in najslabša ocena ne upoštevata.
Mirko ima več kot dovolj dela z iskanjem primernih sodnikov (pa še z njegovo matematiko je
bolj tako, tako ...). Zato mu pomagaj in sestavi funckijo točkeSlog(oc1,oc2, oc3, oc4, oc5)
,
ki za danih 5 ocen določi točke za slog.
Namig: Poleg funkcije min
Python pozna tudi funkcijo max
, ki se obnaša podobno!
def točkeSlog(oc1,oc2, oc3, oc4, oc5): '''Koliko točk za slog je dobil skakalec''' vseSkupaj = oc1 + oc2 + oc3 + oc4 + oc5 najslabša = min(oc1,oc2, oc3, oc4, oc5) najboljša = max(oc1,oc2, oc3, oc4, oc5) return vseSkupaj - najslabša - najboljša
ITM oz. indeks telesne mase je številka, s katero lahko v grobem ocenimo
stanje prehranjenosti pri odraslih ljudeh. Če je
Težo, ki je podana v kilogramih, imamo zapisano v spremenljivki masa
.
Višino, ki je podana v centimetrih, pa imamo v spremenljivki visina
.
Sestavite program, ki prebere težo in višino, izračuna ITM in vam pove, v kateri razred
prehranjenosti spadate. Izračunani ITM izpišite na dve decimalni mesti
natančno, tako da uporabite funkcijo dve_decimalki
def dve_decimalki(x):
""" Funkcija vrne niz, ki vsebuje zapis decimalnega števila x
na dve decimalni mesti natančno. """
return '{0:.2f}'.format(x)
Izpis naj bo sledeč:
Ti si podhranjen.
Ti si normalno prehranjen.
Ti si čezmerno prehranjen.
Ti si debel.
Primer: Za podatke masa = 82.5
, visina = 185.3
naj program izpiše:
>>>Vnesi težo: 82.5
Vnesi višino: 185.3
Tvoj ITM: 24.03
Ti si normalno prehranjen.
def dve_decimalki(x): """ Funkcija vrne niz, ki vsebuje zapis decimalnega števila x na dve decimalni mesti natančno. """ return '{0:.2f}'.format(x) masa = float(input('Vnesi težo: ')) visina = float(input('Vnesi višino: ')) itm = masa / (visina / 100)**2 print('Tvoj ITM:', dve_decimalki(itm)) if itm < 18.5: print('Ti si podhranjen.') elif itm < 25: print('Ti si normalno prehranjen.') elif itm < 30: print('Ti si čezmerno prehranjen.') else: print('Ti si debel.')
Napiši funkcijo finStanje(n)
, ki kot argument sprejme količino denarja
na bančnem računu, podano v evrih (celih) in slovničnemu številu
ustrezno vrne opis finančnega stanja.
>>>finStanje(1)
Stanje: 1 evro.
>>>finStanje(1002)
Stanje: 1002 evra.
>>>finStanje(-203)
Stanje: -203 evri.
>>>finStanje(215)
Stanje: 215 evrov.
Primer, če je vneseno stanje večje ali enako 1000000 evrov:
>>>finStanje(1000002)
Tajkun!
Primer, če je vneseno stanje nižje od -300 evrov:
>>>finStanje(-302)
Ti si navadna zguba!
def finStanje(n): '''vrne opis finančnega stanja''' if n <-300: return 'Ti si navadna zguba!' if n >= 1000000: return 'Tajkun!' if abs(n)%100 == 1: return 'Stanje: ' + str(n) +' evro.' if abs(n)%100 == 2: return 'Stanje: ' + str(n) + ' evra.' if abs(n)%100 == 3 or abs(n)%100 == 4: return 'Stanje: ' + str(n) + ' evri.' return 'Stanje: ' + str(n) + ' evrov.'
Sestavi funkcijo stLjudi(n)
, ki kot argument sprejme poljubno naravno
število in nato v slovnično pravilni obliki vrne opis števila ljudi
v dvorani kulturnega doma (glej zglede). Dvorana sprejme največ 500 ljudi. Podatki so simeslni, torej
celo število, večje ali enako 0.
Primer za n=0:
Dvorana je prazna.
Primer za n=1:
V dvorani je 1 človek.
Primer za n=303:
V dvorani so 303 ljudje.
Primer za n=500:
Dvorana je polna.
Primer za n=502:
Dvorana je polna. Zunaj sta ostala 2 človeka.
def stLjudi(n): '''vrne niz z opisom števila ljudi v dvorani''' if n == 0: return 'Dvorana je prazna.' if n < 500: if n%100 == 1: return 'V dvorani je '+ str(n) + ' človek.' elif n%100 == 2: return 'V dvorani sta '+ str(n) + ' človeka.' elif n%100 == 3 or n%100==4: return 'V dvorani so '+ str(n) + ' ljudje.' else: return 'V dvorani je '+ str(n) + ' ljudi.' if n==500: return 'Dvorana je polna.' # več kot 500! if n%100 == 1: return 'Dvorana je polna. Zunaj je ostal '+ str(n-500)+' človek.' elif n%100 == 2: return 'Dvorana je polna. Zunaj sta ostala '+ str(n-500)+' človeka.' elif n%100 == 3 or n%100 == 4: return 'Dvorana je polna. Zunaj so ostali '+ str(n-500)+' ljudje.' else: return 'Dvorana je polna. Zunaj je ostalo '+ str(n-500)+' ljudi.'
Sestavite program, ki prebere naravno število n
in nato izpiše niz oblike
Koliko imaš limon: 103
Imaš 103 limone.
Koliko imaš limon: 0
Imaš 0 limon.
pri čemer mora biti seveda vse pravilno sklanjano.
n = int(input('Koliko imaš limon: ')) ostanek = n % 100 if ostanek == 1: koncnica = 'o' elif ostanek == 2: koncnica = 'i' elif ostanek == 3 or ostanek == 4: koncnica = 'e' else: koncnica = '' print("Imaš {0} limon{1}.".format(n, koncnica))
Skupina slovenskih nadebudnih mladih inovatorjev se je domislila projekta biokosmiči. Vrečke, v kateri so shranjeni kosmiči, ni potrebno odpirati, saj se v vodi raztopi. Vrečka je užitna in brez okusa.
Sestavite funkcijo nakup(imam, rabim, vrecka)
, ki izračuna, najmanj koliko
vrečk kosmičev moramo kupiti, če jih že imamo imam
gramov, potrebujemo
jih rabim
gramov, v posamezni vrečki pa je zapakirano vrecka
gramov.
Primer:
>>> nakup(4, 10, 3)
2
def nakup(imam, rabim, vrecka): '''Koliko vrečk kosmičev je potrebno še kupiti''' if imam >= rabim: return 0 # imam več kot rabim ali ravno toliko if (rabim - imam) % vrecka == 0: # v vrečkah je za naše potrebe po idealno kosmičev return (rabim - imam) // vrecka return (rabim - imam) // vrecka + 1 # če se ne izide, je potrebno kupiti še dodatno
Vsaka vrečka vsebuje 125 g kosmičev, ki so sestavljeni iz 80 g ovsenih
kosmičev, 20 g rozin in 25 g oreščkov. Imamo že kosmici
gramov ovsenih
kosmičev, rozine
gramov rozin in orescki
gramov oreščkov. Sestavite
funkcijo napolni(kosmici, rozine, orescki, n)
, ki izračuna, koliko
gramov ovsenih kosmičev, rozin in oreščkov moramo še kupiti, da bomo
lahko napolnili n
vrečk kosmičev (funkcija mora vrniti trojico
vrednosti). Primer:
>>> napolni(300, 0, 65, 3)
(0, 60, 10)
def napolni(kosmici, rozine, orescki, n): '''Koliko sestavin je še potrebnih za n vrečk''' vreckaKosmici = 80 vreckaRozine = 20 vreckaOrescki = 25 n1 = max(0, vreckaKosmici * n - kosmici) n2 = max(0, vreckaRozine * n - rozine) n3 = max(0, vreckaOrescki * n - orescki) return n1, n2, n3
Sestavite funkcijo napolni2(kosmici, rozine, orescki)
, ki izračuna,
najmanj koliko vrečk kosmičev moramo napolniti, da bomo porabili vse
sestavine. Imamo že kosmici
gramov ovsenih kosmičev, rozine
gramov
rozin in orescki
gramov oreščkov. Manjkajoče sestavine lahko pri tem
dokupimo. Primer:
>>> napolni2(100, 40, 65)
3
def napolni2(kosmici, rozine, orescki): '''Koliko vrečk potrebujemo, da porabimo prav vse sestavine''' vreckaKosmici = 80 vreckaRozine = 20 vreckaOrescki = 25 potrebnoZaKosmice = kosmici // vreckaKosmici potrebnoZaRozine = rozine // vreckaRozine potrebnoZaOrescke = orescki // vreckaOrescki # če se s sestavinami ne sezide, bomo potrebovali še eno vrečko if kosmici % vreckaKosmici > 0: potrebnoZaKosmice += 1 if rozine % vreckaRozine > 0: potrebnoZaRozine += 1 if orescki % vreckaOrescki > 0: potrebnoZaOrescke += 1 # vzamemo največje število potrebnih vrečk return max(potrebnoZaKosmice, potrebnoZaRozine, potrebnoZaOrescke)
Sestavite funkcijo milimetri(kolicina, enota)
, ki razdaljo, podano
z argumentoma kolicina
in enota
, pretvori v milimetre. Pri tem je
kolicina
neko število, enota
pa je eden od nizov 'm'
, 'dm'
,
'cm'
ali 'mm'
, ki predstavlja enoto. Primer:
>>> milimetri(3, 'm')
3000
>>> milimetri(15, 'cm')
150
def milimetri(kolicina, enota): '''Koliko mm je to?''' if enota == 'm': odg = 1000 * kolicina elif enota == 'dm': odg = 100 * kolicina elif enota == 'cm': odg = 10 * kolicina else: odg = kolicina return odg def milimetriV2(kolicina, enota): '''Koliko mm je to?''' if enota == 'm': odg = 1000 * kolicina elif enota == 'dm': odg = 100 * kolicina elif enota == 'cm': odg = 10 * kolicina else: odg = kolicina return odg
Sestavite funkcijo milimetriV2(kolicina, enota)
, ki razdaljo, podano
z argumentoma kolicina
in enota
, pretvori v milimetre. Pri tem je
kolicina
neko število, enota
pa je zagotovo eden od nizov 'm'
, 'dm'
,
'cm'
ali 'mm'
, ki predstavlja enoto. Primer:
>>> milimetri(3, 'm')
3000
>>> milimetri(15, 'cm')
150
Pri tem ne smeš uporabiti ne gnezdenih stavkov if, ne dela else. Namig: v funkciji imamo
lahko več ukazov return
def milimetriV2(kolicina, enota): '''Koliko mm je to?''' if enota == 'm': return 1000 * kolicina # če smo prišli sem - m zagotovo niso if enota == 'dm': return 100 * kolicina if enota == 'cm': return 10 * kolicina # torej gre za mm return kolicina
Sestavite funkcijo primerjaj(mera1, enota1, mera2, enota2)
, ki za dve podani
razdalji pove, katera je večja. Prva razdalja je podana v
spremenljivkah mera1
in enota1
, druga pa v spremenljivkah mera2
in enota2
Funkcija naj vrne prva
, če je prva razdalja večja od druge; enaki
,
če sta razdalji enaki in druga
, če je druga razdalja večja od prve.
Primer:
>>> primerjaj(2, 'm', 3, 'm')
druga
>>> primerjaj(1, 'm', 100, 'cm')
enaki
def primerjaj(mera1, enota1, mera2, enota2): '''Katera razdalja je večja''' # pretvorimo obe razdalji v mm razlika = milimetri(mera1, enota1) - milimetri(mera2, enota2) if razlika > 0: return 'prva' if razlika < 0: return 'druga' # ni se izvedel noben izmed gornjih ukazov return, torej ni bil izpolnjen noben pogoj... return 'enaki'
Sestavite funkcijo primerjajEnoti(enota1, enota2)
, ki za dve
dolžinski enoti pove, katera je večja. Funkcija naj vrne 1
, če je
prva enota večja od druge, 0
, če sta enoti enaki, in -1
, če je
druga enota večja od prve. Primer:
>>> primerjajEnoti('dm', 'cm')
1
>>> primerjajEnoti('mm', 'm')
-1
Namig: Neposredno primerjanje nizov bo dalo napačen rezultat!
def primerjajEnoti(enota1, enota2): '''1 - večja je enota1 0 - enaki enoti -1 - večja je enota2 ''' primerjava = primerjaj(1, enota1, 1, enota2) # uporabimo funkcijo prejšnje naloge if primerjava == 'prva': return 1 if primerjava == 'druga': return -1 return 0
Indiana Jones najde v starem templju tri zlate kipce, ker pa ima samo
dve roki, mora enega, katerega vrednost je najmanjša, pustiti tam.
Sestavi funkcijo indiana(stevilo1, stevilo2, stevilo3)
, ki kot argumente
sprejme vrednosti kipcev ter vrne podatek (niz) katera dva kipca se
najbolj splača vzeti s sabo.
Možne rešitve so:
če so vrednosti kipcev različne, ali če se dve vrednosti ponovita in sta večji od tretje:
"Vzeti mora kipca 2 in 3."
"Vzeti mora kipca 1 in 3."
"Vzeti mora kipca 1 in 2."
če so vrednosti vseh kipcev enake:
"Vzame lahko katerakoli dva kipca."
če se dve vrednosti ponovita in sta manjši od tretje:
"Vzeti mora kipec 3 ter enega od preostalih dveh."
"Vzeti mora kipec 2 ter enega od preostalih dveh."
"Vzeti mora kipec 1 ter enega od preostalih dveh."
def indiana(stevilo1, stevilo2, stevilo3): '''vrne podatek, katera kipca se splača vzeti''' #če so vrednosti vseh kipcev enake, vzamemo poljubna kipca if stevilo1 == stevilo2 == stevilo3: return "Vzame lahko katerakoli dva kipca." #če je vrednost prvega kipca manjša od ostalih, izločimo prvi kipec #podobno naprej if stevilo1 < min(stevilo2, stevilo3): return "Vzeti mora kipca 2 in 3." if stevilo2 < min(stevilo1, stevilo3): return "Vzeti mora kipca 1 in 3." if stevilo3 < min(stevilo1, stevilo2): return "Vzeti mora kipca 1 in 2." #če se dve vrednosti ponovita, potem ločimo primer, ko je tretja vrednost ali večja ali manjša od prvih dveh #če je manjša, vzamemo kipca s prvima dvema vrednostima #če je večja, vzamemo kipec s tretjo vrednostjo in izbiramo med ostalima kipcema if (stevilo1 == stevilo2) and (stevilo3 != stevilo2): if stevilo1 < stevilo3: return "Vzeti mora kipec 3 ter enega od preostalih dveh." else: return "Vzeti mora kipca 1 in 2." if (stevilo1 == stevilo3) and (stevilo3 != stevilo2): if stevilo1 < stevilo2: return "Vzeti mora kipec 2 ter enega od preostalih dveh." else: return "Vzeti mora kipca 1 in 3." if (stevilo2 == stevilo3) and (stevilo1 != stevilo2): if stevilo2 < stevilo1: return "Vzeti mora kipec 1 ter enega od preostalih dveh." else: return "Vzeti mora kipca 2 in 3."
Sedaj pa sestavi funkcijo izguba(stevilo1, stevilo2, stevilo3)
, ki kot argumente
sprejme vrednosti kipcev ter vrne koliko bo Indiana Jones žal moral pustiti v templju
Tako:
>>>izguba(7, 2, 3)
2
>>>izguba(7, 8, 7)
7
def izguba(stevilo1, stevilo2, stevilo3): '''vrne vrednost, ki jo bo Indiana Jones moral pustiti''' return min(stevilo1, stevilo2, stevilo3)
Sedaj pa sestavi funkcijo kateriVrednosti(stevilo1, stevilo2, stevilo3)
, ki kot argumente
sprejme vrednosti kipcev ter vrne po velikosti urejen par vrednosti kipcev, ki ju bo Indiana Jones
vzel
Tako:
>>>kateriVrednosti(7, 2, 3)
(3, 7)
>>>kateriVrednosti(7, 8, 7)
(7, 8)
def kateriVrednosti(stevilo1, stevilo2, stevilo3): '''vrne vrednost, ki jo bo Indiana Jones moral pustiti''' najv = max(stevilo1, stevilo2, stevilo3) najm = min(stevilo1, stevilo2, stevilo3) srednje = stevilo1 + stevilo2 + stevilo3 - najv - najm return (srednje, najv)
Sestavite funkcijo nad_interval(a1, b1, a2, b2)
, ki izračuna najmanjši
interval, ki vsebuje intervala
Primer:
>>> nad_interval(3, 7, 1, 2)
(1, 7)
>>> nad_interval(3, 7, 1, 5)
(1, 7)
>>> nad_interval(3, 7, 7, 8)
(3, 8)
def nad_interval(a1, b1, a2, b2): '''interval, ki vsebuje oba dana intervala''' a3 = min(a1, a2) b3 = max(b1, b2) return (a3, b3)
Sestavite funkcijo presek_intervalov(a1, b1, a2, b2)
, ki izračuna
največji interval, vsebovan v intervalih
Primer:
>>> presek_intervalov(3, 7, 1, 2)
(0,-1)
>>> presek_intervalov(3, 7, 1, 5)
(3, 5)
>>> presek_intervalov(3, 7, 7, 8)
(7, 7)
def presek_intervalov(a1, b1, a2, b2): '''Vrne presek intervalov (če obstaja), sicer pa (0,-1)''' a3 = max(a1, a2) b3 = min(b1, b2) if a3 > b3: return (0,-1) else: return (a3, b3)
Sestavi funkcijo pravokotnika(a1x, a1y, b1x, b1y, a2x, a2y, b2x, b2y)
,
ki bo izračunala obseg in površino unije dveh pravokotnikov. Stranice
pravokotnikov so vzporedne koordinatnima osema. Vsak pravokotnik je
podan s koordinatami (katerihkoli) dveh nasprotnih si oglišč.
Primer:
>>> pravokotnika(1, 1, 5, 5, 6, 8, 8, 3)
(30, 26)
>>> pravokotnika(1, 1, 5, 5, 4, 8, 8, 3)
(28, 34)
def pravokotnika(a1x, a1y, b1x, b1y, a2x, a2y, b2x, b2y): '''Izračuna obseg in površino unije dveh pravokotnikov''' # poskrbimo, da je A1 levo spodaj in B1 desno zgoraj if a1x > b1x: a1x, b1x = b1x, a1x if a1y > b1y: a1y, b1y = b1y, a1y # poskrbimo, da je A2 levo spodaj in B3 desno zgoraj if a2x > b2x: a2x, b2x = b2x, a2x if a2y > b2y: a2y, b2y = b2y, a2y # določimo točki, ki določata presek A3 je levo spodaj in B3 desno zgoraj # če preseka ni, sta seveda ti točki "čudni" ax3 = max(a1x, a2x) ay3 = max(a1y, a2y) bx3 = min(b1x, b2x) by3 = min(b1y, b2y) # izračunamo ploščino prvega in drugega pravok pl1 = (b1x - a1x) * (b1y - a1y) pl2 = (b2x - a2x) * (b2y - a2y) ob1 = 2 * ((b1x - a1x) + (b1y - a1y)) ob2 = 2 * ((b2x - a2x) + (b2y - a2y)) # izračunamo pl in obseg preseka pl3 = 0 ob3 = 0 # pogledamo, če sploh presek je! Dovolimo tudi samo črto (torej če ene stranuice "ni")! if bx3 >= ax3 and by3 >= ay3: pl3 = (bx3 - ax3) * (by3 - ay3) ob3 = 2 * ((bx3 - ax3) + (by3 - ay3)) obsegRezultata = ob1 + ob2 - ob3 ploscinaRezultata = pl1 + pl2 - pl3 return(obsegRezultata, ploscinaRezultata)
Za nalogo potrebuješ le znanje definiranja funkcij in stavka if
Matej se rad igra s kamenčki in jih cel dan nabira naokrog. Zvečer pa ga neskončno zabava, ko njegov mljši brat poskuša uganiti, koliko jih je nabral.
Če brat pove premajhno število, mu Matej odgovori 'več'
, če pove
preveliko število, mu Matej odgovori 'manj'
, če pa število ugane mu Matej
odgovori 'točno'
.
Setavite funkcijo ugibaj(matej, brat)
, ki simulira en korak zgornje igre.
Funkcija naj Matejev odgovor vrne kot niz.
Primer:
>>> ugibaj(8, 5)
'več'
def ugibaj(matej, brat): '''Kako odgovori Matej''' if matej > brat: return 'več' elif matej < brat: return 'manj' else: return 'točno'
Da bi igro popestril, je Matej razdelil kamenčke v obe roki, brat pa mora uganiti število kamenčkov v vsaki roki posebej. Ob vsakem poskusu Matej za vsako izmed rok izračuna absolutno razliko med pravim številom kamenčkov in bratovim poskusom ter bratu pove manjše izmed teh dveh števil.
Sestavite funkcijo ugibaj1(matejLR, matejDR, bratLR, bratDR)
, ki sprejme štiri nenegativna
cela števila in Matejev odgovor vrne kot število. Če brat ugane obe števili,
naj funkcija vrne -100.
Primer:
>>> ugibaj1(8, 10, 5, 3)
5
import math def ugibaj1(matejLr, matejDr, bratLr, bratDr): '''Kakšna je največja razlika''' razlika1 = abs(matejLr - bratLr) razlika2 = abs(matejDr - bratDr) najvecja = min(razlika1, razlika2) if najvecja == 0: # uganjeni sta obe return -100 return najvecja
Zgornja igra pa ni bila preveč všeč Matejevemu bratu, saj je običajno trajala
predolgo in je zato brat še pred koncem igre že zaspal. Zato je od Mateja
zahteval, da mu za vsako roko pove še, ali je število kamenčkov v njej večje,
manjše oz. enako ugibanemu. Mateju pa se je to zdelo preveč, zato sta
se odločila za kompromis: Matej bo bratu povedal le, ali je brat
obakrat povedal preveliko število, obakrat premajhno ali pa enkrat premajhno
in drugič preveliko. Ustrezni Matejevi odgovori so 'Obakrat preveč.'
,
'Obakrat premalo.'
in 'Preveč in premalo.'
. Če brat ugane eno izmed
števil, drugega pa ne, se Matej pretvarja, kot da je brat namesto pravega
števila povedal preveliko število.
Sestavite funkcijo ugibaj2(matejLr, matejDr, bratLr, bratDr)
, ki sprejme štiri
nenegativna cela števila in Matejev odgovor vrne kot niz. Če brat ugane obe števili, naj
funkcija vrne niz 'Bravo!'
Primer:
>>> ugibaj2(4, 3, 4, 6)
'Obakrat preveč'
def ugibaj2(matejLr, matejDr, bratLr, bratDr): '''Kaj odgovori Matej''' razlika1 = bratLr - matejLr razlika2 = bratDr - matejDr if razlikaLr == 0 and razlikaDr == 0: return 'Bravo!' elif razlikaLr >= 0 and razlikaDr >= 0: return 'Obakrat preveč.' elif razlikaLr < 0 and razlikaDr < 0: return 'Obakrat premalo.' else: return 'Preveč in premalo.' def ugibaj2(matejLr, matejDr, bratLr, bratDr): '''Kaj odgovori Matej''' # za razliko od prej, upoštevamo, da return zaključi funkcijo, torej ne potrebujemo elif razlikaLr = bratLr - matejLr razlikaDr = bratDr - matejDr if razlikaLr == 0 and razlikaDr == 0: return 'Bravo!' if razlikaLr >= 0 and razlikaDr >= 0: return 'Obakrat preveč.' if razlikaLr < 0 and razlikaDr < 0: return 'Obakrat premalo.' return 'Preveč in premalo.'
Če na začetek programa napišemo
import time
bomo, med drugim, dobili funkcijo time
, ki s klicem time.time()
vrne čas v sekundah
od nekega trenutka v davni preteklosti.
Kako hitro razmišljamo
Napiši program, ki uporabnika vpraša, koliko je a
krat b
. pri tem sta a
inb
dve naključni
enomestni naravni števili. Uporabnik bo premislil in vpisal odgovor.
Program naj izpiše, koliko sekund je človek potreboval za razmišljanje, ter, če je odgovor pravilen.
Namig: če veš, koliko je bila ura pred klicem funkcije input in koliko je bila ura po klicu,
znaš izračunati, koliko časa je minilo vmes.
>>>Koliko je 6 x 7: 42
Čestitam! Odgovor je pravilen. Za odgovor si potreboval 2.503019332885742 s.
import time import random a = random.randint(1, 9) b = random.randint(1, 9) začetek = time.time() odg = int(input('Koliko je ' + str(a) + ' x ' + str(b) + ': ')) konec = time.time() if odg == a * b: print('Čestitam! Odgovor je pravilen.', end = " ") else: print('Žal narobe! Prav je ' + str(a*b) + '!', end = " ") print('Za odgovor si potreboval', konec - začetek, 's')
Misleči stroj I
Oglej si, kaj počne naslednji program:
import time
a = int(input('Prvo število: '))
b = int(input('Drugo število: '))
print('Računam ...')
time.sleep(3)
print('Uf, je bilo težko. V 3 sek so se moji čipi pošteno ogreli. Rezultat je:', a*b)
nato ga spremeni tako, da bo računalnik razmišljal med 1 in 5 sekundami! Pri tem lahko čaka tudi npr. 4.371232 sekunde ali pa točno 5! Oglej si dokumentacijo in poišči ustrezno funkcijo. Čas razmišljanja izpiši zaokroženo na tisočinke!
import time import random a = int(input('Prvo število: ')) b = int(input('Drugo število: ')) print('Računam ...') časČakanja = random.uniform(1, 5) time.sleep(časČakanja) print('Uf, je bilo težko. V', round(časČakanja,3), 'sek so se moji čipi pošteno ogreli. Rezultat je:', a*b)
Misleči stroj II
Večji kot je produkt, težji je račun. Računalnik naj zato čaka toliko sekund, kolikor je velik produkt, deljeno z 10. Če mu damo množiti 6 in 7, naj pred izpisom počaka 4.2 sekunde. Če je katero od števil negativno, naj vedno čaka 2 sekundi več, kot bi čakal pri pozitivnih številih. V nobenem primeru pa čas čakanja ne sme biti več kot 10 sekund.
Izpis naj bo tak, kot ga predvideva zgornji program!
import time a = int(input('Prvo število: ')) b = int(input('Drugo število: ')) print('Računam ...') časČakanja = abs(a * b) / 10 if a < 0 or b < 0: # za negativna števila časČakanja = časČakanja + 2 if časČakanja > 10: časČakanja = 10 time.sleep(časČakanja) print('Uf, je bilo težko. V', časČakanja, 'sek so se moji čipi pošteno ogreli. Rezultat je:', a*b)
Okulist Tone želi svojim strankam poslati program za kontrolo vida. Napiši mu program, ki bo izpisal med 10 in 20 znakov *, ločenih s presledki. Uporabnik jih mora prešteti in vnesti odgovor. Na podlagi odgovora naj program izpiše, ali mora uporabnik k okulistu Tonetu ali ne.
>>>* * * * * * * * * *
Koliko * vidite: 11
Prosim, zglasite se pri okulistu Tonetu.
>>>* * * * * * * * * * * * *
Koliko * vidite: 13
Vaš vid je še dober.
import random koliko = random.randint(10, 20) vzorec = '* ' * koliko print(vzorec) odg = int(input('Koliko * vidite: ')) if odg == koliko: print('Vaš vid je še dober.') else: print('Prosim, zglasite se pri okulistu Tonetu.')
Nek izdelek naj bi se vsak teden podražil za 2%. Da bi razumeli, kaj to
pomeni, napiši funkcijo kolikoTednov(cena)
, ki za dano začetno ceno (v €)
tega izdelka vrne število tednov, ko bo cena dosegla ali presegla 1000€.
V dobrih 6 letih bi se to zgodilo s kavo, ki sedaj stane 1€!
Za šaljivce, ki bodo funkcijo poklicali z negativno ceno, vrni -1
def kolikoTednov(cena): ''' v koliko tednih se ob 2% tedenski podražitvi cena dvigne nad 1000€''' končnaCena = 1000 trenutnaCena = cena tednov = 0 if trenutnaCena < 0: return -1 while trenutnaCena < končnaCena: trenutnaCena = trenutnaCena * 1.02 tednov += 1 # to je isto kot tednov = tednov + 1 return tednov
Bakteriolog Bine preučuje bakterije. Naredil je sledeči poizkus: bakterije je zaprl v škatlico pravokotne oblike s pregrado na sredini, ki razdeli škatlico na dva kvadratna dela - poimenujmo ju regija A in regija B. Zunanje stene te škatlice so polprepustne, kar pomeni, da bacili lahko uidejo ven, vendar se ne morejo vrniti v škatlico, pregrada pa je prepustna, tj. bacili lahko prehajajo v obe smeri. Bine predvideva, da v neki časovni enoti 12 % vseh bacilov ostane v svoji regiji, po 22 % pa jih zapusti svojo regijo v vsaki od štirih smeri. Binetu sestavi program, ki bo prebral začetni masi bacilov (bacili so premajhni, da bi jih # šteli posamično, zato jih "štejemo" kar v gramih) v vsaki od regij in izpisal število korakov, dokler skupna masa bacilov v obeh regijah ne pade pod 0.001 grama. Tako bo lahko Bine primerjal teoretični izračun z izmerjenimi podatki in preveril svojo hipotezo. Predpostavi, da so podatki pravilni (nenegativni!
Pozor! Premisli, kaj se dogaja na pregradi!
Za začetni masi 22.4 in 13.5 se število bakterij giblje
1, 5.658, 6.548
2, 2.11952, 2.03052
3, 0.7010568, 0.7099568
4, 0.240317312, 0.239427312
5, 0.08151208608, 0.08160108608
6, 0.0277336892672, 0.0277247892672
7, 0.00942749635085, 0.00942838635085
8, 0.00320554455929, 0.00320545555929
9, 0.00108986557016, 0.00108987447016
10 0.0003035929996319583 0.0003035829997319583
zato bi program izpisal 10. Primer:
>>>Masa v regiji A: 22.4
Masa v regiji B: 13.5
Korakov: 10
# Določimo število tednov, ko se ustrezno zmanjša začetna porazdelitev bakterij masaA = float(input('Masa v regiji A: ')) masaB = float(input('Masa v regiji B: ')) korak = 0 while masaA + masaB >= 0.001: # skupna teža je še prevelika staraA = masaA # potrebovali bomo za izračun B-ja masaA = masaA * 0.12 # toliko jih ostane masaA = masaA + masaB * 0.22 # toliko jih pa še pride iz B masaB = masaB * 0.12 masaB = masaB + staraA * 0.22 korak += 1 # en korak več print('Korakov:', korak)
Sestavite funkcijo vsotaKvadratov(n)
, ki izračuna in vrne vsoto
>>> vsotaKvadratov(10)
385
def vsotaKvadratov(n): '''Vsota kvadratov''' s = 0 for i in range(1, n + 1): # začnemo pri 1 in končamo pri n s += i * i return s def vsotaKvadratovMat(n): '''No, če ste malo bolj "doma" v matematiki, je vaša rešitev seveda ''' return n * (n + 1) * (2*n + 1) // 6
Sestavite funkcijo vsota(n)
, ki izračuna in vrne vsoto
>>> vsota(10)
440
def vsota(n): '''Vsota vrste ''' s = 0 for i in range(1, n + 1): # začnemo pri 1 in končamo pri n s += i * (i + 1) return s
Sestavite funkcijo stevilo_clenov(m)
, ki izračuna, največ koliko
členov vsote m
.
Primer:
>>> stevilo_clenov(20)
3
def stevilo_clenov(m): '''Koliko členov vrste lahko seštejemo, da ne presežemo meje m''' vsotaVrste = 0 if m < 1: # ne smemo sešteti nobenega return 0 stČlenov = 0 while vsotaVrste <= m: stČlenov += 1 vsotaVrste += stČlenov * (stČlenov + 1) return stČlenov - 1 # z zadnjim smo že presegli mejo
Sestavite funkcijo najblizje(a, b, m)
, ki poišče takšno število k
med a
in b
, pri katerem se z eno od delnih vsot
m
. Če je takšnih števil več, naj funkcija
vrne najmanjšega. Primer:
>>> najblizje(10, 20, 10000)
14
def blizina(k, m): '''Kako najbližje se lahko z $k\cdot(k+1) + (k+1)\cdot(k+2) + (k+2)\cdot(k+3) + \ldots$ približamo meji m ''' sZgoraj = 0 while sZgoraj <= m: # nehali bomo, ko bomo presegli mejo sZgoraj += k * (k + 1) k += 1 sSpodaj = sZgoraj - (k - 1) * k # če se ustavimo prej, še ne presežemo m return min(sZgoraj - m, m - sSpodaj) # ali smo se meji bolj približali od spodaj, ali od zgoraj def najblizje(a, b, m): '''Kje med a in b moramo začeti sešetvati člene vrste, da se najbolj približamo meji m''' najmanRaz, najK = blizina(a, m), a # kandidat je a for k in range(a + 1, b + 1): # še preostale razdalja = blizina(k, m) if razdalja < najmanRaz: # našli smo boljšega kandidata najmanRaz = razdalja najK = k return najK
Sestavi funkcijo obrniStevilo(n)
, ki obrne pozitivno celo število.
Iz 234 torej naredi število 432. Če je podatek slučajno negativen, vrni 0!
Tisti, ki že poznate funcije in metode za delo z nizi, teh prijemov tukaj ne smete uporabiti. V tej nalogi torej nikjer ne smemo uporabljati nizov!
def obrniStevilo(n): ''' Funkcija obrne pozitivno celo število''' if n < 0: return 0 obrnjeno = 0 while n > 0: obrnjeno = obrnjeno * 10 + n % 10 n = n // 10 return obrnjeno
Najprej si oglej naslednjo funkcijo. Ugotovi, kaj počne! Očitno jo je pisal nek programer začetnik, kar lahko zlahka ugotovimo po odsotnosti komentarjev in izbiri imen spremenljivk
def f(a, b):
d = a % b # koliko še ostane
k = 0
r = '.'
while k <= 10:
d = d * 10
nd = d // b
r = r + str(nd)
k = k + 1
d = d % b
return r
Namig: pokliči jo s parametri 7, 3; 2, 4; 15, 7; 1, 3; 2, 3; 3, 3 in poskusi postaviti hipotezo, kaj se dogaja ...
Oborožen z vedenjem o zgornji funkciji
sestavi funkcijo kvocient(a, b, n)
, ki bo vrnila celi del in prvih n decimalk
kvocienta a/b v obliki niza.
Delaj samo s pozitivnimi celimi števili in na koncu NE zaokrožuj
>>>kvocient(10, 761, 40)
0.0131406044678055190538764783180026281208
>>>kvocient(100, 3, 14)
33.33333333333333
Namig: kako delimo "peš"?
def kvocient(a, b, n): '''Izračunamo a/b na n decimalk (za dec. piko)''' celiDel = a // b rezultat = str(celiDel) + '.' delimo = a % b # koliko še ostane decimalke = 0 while decimalke < n: # koliko decimalk potrebujemo delimo = delimo * 10 novaDec = delimo // b rezultat = rezultat + str(novaDec) # dodamo decimalko decimalke = decimalke + 1 # je ena več delimo = delimo % b # za naslednji korak return rezultat
Programer Mihec je sestavil funkcijo vsebuje(a, k)
, ki naj bi povedala
(True/False) če poljubno celo število a
vsebuje števko k.
def vsebuje(stevilo, k):
''' ali število stevilo vsebuje števko k '''
while stevilo > 0:
if stevilo % 10 == k:
return True
stevilo = stevilo // 10
return False
Preizkusil jo je na storitvi Projekt Tomo, a je kar naprej dobival obvestila o napačnem rezultatu. Preizkusi jo še ti in jo ustrezno popravi!
def vsebuje(stevilo, k): ''' ali število stevilo vsebuje števko k ''' if stevilo == k == 0 : return True stevilo = abs(stevilo) # zaradi neg. števil! while stevilo > 0: if stevilo % 10 == k: return True stevilo = stevilo // 10 return False
Sestavi funkcijo prestejVsebuje(a,b,k)
, ki prešteje,
koliko števil med a
in b
(meji vključeni)
vsebuje števko k.
A pozor, lahko je tudi a
>= b
def prestejVsebuje(a, b, k): ''' prešteje koliko je med a in b števil, ki vsebujejo števko k ''' mini = min(a, b) maksi = max(a, b) stevilo = mini koliko = 0 # koliko jih zadošča pogoju while stevilo <= maksi: if vsebuje(stevilo, k): koliko += 1 stevilo = stevilo + 1 return koliko
Sestavi funkcijo prestejPrave(a,b,k)
, ki prešteje,
koliko števil med a
in b
(0 <= a
<= b
), meji vključeni,
vsebuje števko k ali pa so ona ali pa njihovi obrati deljivi s k.
def vsebuje(stevilo, k): ''' ali število stevilo vsebuje števko k ''' if stevilo == k == 0 : return True while stevilo > 0: if stevilo % 10 == k: return True stevilo = stevilo // 10 return False def obrniStevilo(n): ''' Funkcija obrne pozitivno celo število''' obrnjeno = 0 while n > 0: obrnjeno = obrnjeno * 10 + n % 10 n = n // 10 return obrnjeno def prestejPrave(a, b, k): ''' prešteje koliko je med a in b števil, ki zadoščajo pogoju k ''' stevilo = a koliko = 0 # koliko jih zadošča pogoju while stevilo <= b: if vsebuje(stevilo, k) or stevilo % k == 0 or obrniStevilo(stevilo) % k == 0: koliko += 1 stevilo = stevilo + 1 return koliko
Pravimo, da sta števili
Približek števila
Sestavite funkcijo naslednjiPriblizek(x)
, ki iz približka x
po
zgornjem postopku izračuna naslednji približek števila
def naslednjiPriblizek(x): '''Naslednji približek za zlati rez''' return 1 + 1 / x
Sestavite funkcijo priblizek(k)
, ki izračuna k
. približek števila
k
enak
def priblizek(k): '''K-ti približek za zlati rez, če začnemo z 1''' x = 1 poskus = 1 #kateri člen zaporedja while poskus <= k: x = naslednjiPriblizek(x) poskus += 1 return x
Sestavite funkcijo natancniPriblizek(eps)
, ki izračuna prvi približek
števila eps
.
def natancniPriblizek(eps): '''Približek, ki se od prejšnjega razlikuje za manj kot eps (začnemo z 1)''' prejsnji = 1 naslednji = naslednjiPriblizek(prejsnji) while abs(prejsnji - naslednji) >= eps: prejsnji = naslednji # zadnji je za naslednji korak prejšnji naslednji = naslednjiPriblizek(prejsnji) return naslednji
Približke za kvadratni koren števila
Sestavite funkcijo priblizek(n, k)
, ki po zgornjem postopku izračuna
k
. približek korena števila n
.
def priblizek(n, k): '''K-ti približek za kvadratni koren''' trenutniPrib = n / 2 i = 0 while i < k: trenutniPrib = (trenutniPrib + n / trenutniPrib) / 2 i = i + 1 return trenutniPrib
Sestavite funkcijo koren(n, eps)
, ki po zgornjem postopku izračuna
prvi približek korena števila n
, za katerega se kvadrat približka od n
razlikuje za manj kot eps
. Smislena vrednost za argument eps
je npr.
def koren(n, eps): '''Približek za koren na eps natančno''' priblizek = n / 2 while abs(priblizek ** 2 - n) > eps: priblizek = (priblizek + n / priblizek) / 2 return priblizek
S pomočjo naključnih števil bomo določili število π
Približek za število π lahko določimo tako, da izberemo n
naključnih točk
v kvadratu [0,1]×[0,1], ter preštejemo, koliko jih leži v krogu s središčem
v (0,0) in polmerom 1. Če je n
dovolj velik, mora biti razmerje med številom
točk v krogu in številom vseh točk približno π/4, saj z veliko točkami
"pokrijemo" kvadrat oz. del kroga, ki imata ploščini 1 oziroma π/4.
Sestavi funkcijo približekPi(stTočk)
, ki izračuna približek za število π po
opisani metodi. Število naključnih točk funkcija dobi kot parameter.
Seveda math.pi
nima v vaši funkciji kaj početi!
import random def približekPi(stTočk): '''S simulacijo izbire stTočk določi približek za Pi''' kolikoVKrogu = 0 stPoskusa = 1 while stPoskusa <= stTočk: # naredimo toliko "poskusov" # naključna točka v kvadratu x = random.random() y = random.random() razdalja = x*x + y*y if razdalja <= 1 : kolikoVKrogu += 1 stPoskusa = stPoskusa + 1 # izračunamo razmerje razm = kolikoVKrogu / stTočk return razm * 4
Sestavi funkcijo dvakratZapored()
, ki vrne kolikokrat smo
vrgli kocko, da smo dvakrat zapored vrgli 6. če npr. mečemo
2, 6, 3, 4, 6, 4, 5, 6, 6, ...
smo torej kocko morali vreči 9x, da smo dvakrat zapored vrgli 6.
import random def dvakratZapored(): '''Kolikometov je potrebnih, da dvakrat zapored vržemo 6''' številoMetov = 0 prejšniMet = 42 # koliko smo vrgli v prejšnem metu (karkoli razen 6!) while True : # kar neskončna zanka, izstopili bomo z return met = random.randint(1,6) številoMetov += 1 if (met == 6) and (prejšniMet == 6): return številoMetov prejšniMet = met
Sestavi funkcijo verjetnostDveh6(n)
, ki na podlagi n
klicev prejšnje
funkcije dvakratZapored()
ugotovi,
kolikokrat smo v povprečju v n
poskusih morali vreči kocko, da smo
dvakrat zapored vrgli 6.
import random def verjetnostDveh6(stPoskusov): skupnoŠtMetov = 0 poskus = 1 while poskus <= stPoskusov: številoMetov = dvakratZapored() # opravimo eno poskus skupnoŠtMetov = skupnoŠtMetov + številoMetov poskus = poskus + 1 # verjetnost return skupnoŠtMetov / stPoskusov
Ogledali si bomo koliko naključnih števil mora računalnik generirati, da dobi tako s samimi enakimi decimalkami
Spodnja funkcija vrne vsoto prvih petih decimalk števila x.
Pri tem je predpostavka, da pri računanju abs(x - int(x))
ne pride do
zaokrožitvenih napak!!!!!
Predelaj jo v funkcijo z imenom enakeDecimalke(x, k)
tako,
da bo preverila, ali ima realno število x prvih k decimalk enakih.
def vsota(x):
'''Vsota prvih 5 decimalk števila x'''
vs = 0
x = abs(x - int(x))
i = 1
while i <= 5:
x = x * 10
decim = int(x)
vs = vs + decim
x = x - decim
i = i + 1
return vs
Opomba: Načeloma se zadeve ne da narediti čisto prav. Če npr. uradno rešitev preizkusimo na
enakeDecimalke(2.2222,4)
dobimo napačen rezultat! Oglej si zakaj, tako da izračunaš x - int(x)
tega števila.
K nalogi se bomo vrnili kasneje in si pomagali z nizi!
def enakeDecimalke(x, k): ''' ali ima število x prvih k decimalk enakih ''' s = 0 x = abs(x - int(x)) # decimalni del prvaDecimalka = int(x*10) i = 1 while i <= k: x = x * 10 trenutnaDecimalka = int(x) if prvaDecimalka != trenutnaDecimalka : return False # napačna decimalka! x = x - int(x) # še preostale decimalke i = i + 1 return True # vsi testi so bili uspešni
Uporabi funkcijo enakeDecimalke
v novi funkciji z imenom
kolikoGenerirati(k)
, ki bo preštela, koliko naključnih
realnih števil med 0 in 1 moramo generirati, da bomo dobili decimalno število, ki
ima prvih k
decimalk enakih. Funkcija naj vrne tudi to število - vrne torej par
(koliko, nakŠtevilo)
!
import random def kolikoGenerirati(k): koliko = 0 # števec generiranih nak. števil jeUstrezno = False while not jeUstrezno : #Dokler ne bomo naleteli na ustrezno število nakŠtevilo = random.random() koliko += 1 if enakeDecimalke(nakŠtevilo, k) : # je število ustrezno? jeUstrezno = True #skočimo iz zanke return (koliko, nakŠtevilo)
Zavarovalnica zavarovalno premijo za avtomobilska zavarovanja izračuna takole:
Osnovni znesek je 150 €.
K temu se prišteje znesek, ki je odvisen od prijavljenih zavarovalniških zahtevkov stranke v preteklem letu. Če je bil en zahtevek, se prišteje 30 €; če sta bila dva, se prišteje 50 €; za več kot dva zahtevka pa se prišteje 80 €.
Nadalje se k premiji prišteje fiksna vsota 40 €, če je zavarovanec mladi voznik, tj. če je mlajši od 21 let ali pa ima vozniško dovoljenje manj kot dve leti.
Na koncu se še upošteva, če stranka plačilo poravna z gotovino (5 % popust) ali na obroke (7 % več).
Napišite program, ki glede na podatke o stranki (te preberemo tako, kot kaže zgled) izračuna višino premije (zaokroženo na dve decimalki) in jo izpiše.
Primer:
Starost voznika: 25
Koliko let vozniških izkušenj: 5
Koliko zavarovalnih zahtevkov: 2
Način plačila (gotovina/na obroke): gotovina
Premija znaša: 190.0
starost = int(input('Starost voznika: ')) izkusnje = int(input('Koliko let vozniških izkušenj: ')) zahtevki = int(input('Koliko zavarovalnih zahtevkov: ')) placilo = input('Način plačila (gotovina/na obroke): ') premija = 150 # osnovni znesek if zahtevki == 1: premija += 30 elif zahtevki == 2: premija += 50 elif zahtevki > 2: premija += 80 if starost < 21 or izkusnje < 2: premija += 40 if placilo == "gotovina": premija -= 0.05 * premija else: premija += 0.07 * premija print('Premija znaša:', round(premija,2))
Zavarovalni agenti so bili sicer zadovolji s programom, vendar so imeli težave z napačnim vnosom. Zato popravi program tako, da bo:
gotovina
ali na obroke
Primer (tudi tvoj program mora brati podatke v istem vrstnem redu, torej starost, izkušnje, zahtevki, način plačila):
Starost voznika: 15
Starost voznika: 25
Koliko let vozniških izkušenj: 5
Koliko zavarovalnih zahtevkov: 2
Način plačila (gotovina/na obroke): kartica
Način plačila (gotovina/na obroke): pare na sunce
Način plačila (gotovina/na obroke): gotovina
Premija znaša: 190.0
To seveda niso edine kotrole, ki bi bile smislene, a ...
starost = 0 while not (18 <= starost <= 100): starost = int(input('Starost voznika: ')) izkusnje = int(input('Koliko let vozniških izkušenj: ')) zahtevki = int(input('Koliko zavarovalnih zahtevkov: ')) plačilo = '' while plačilo != "gotovina" and plačilo != "na obroke": plačilo = input('Način plačila (gotovina/na obroke): ') premija = 150 # osnovni znesek if zahtevki == 1: premija += 30 elif zahtevki == 2: premija += 50 elif zahtevki > 2: premija += 80 if starost < 21 or izkusnje < 2: premija += 40 if plačilo == "gotovina": premija -= 0.05 * premija else: premija += 0.07 * premija print('Premija znaša:', round(premija,2))
Sestavite funkcijo vsota_stevk(n, k)
, ki vrne vsoto tistih števk
celega števila n
, ki so večje ali enake k
. Kako bi izračunal vsoto vseh števk?
def vsota_stevk(n, k): '''Vrne vsoto števk števila n, ki so večje ali enake k''' vsota = 0 n = abs(n) # za primer negativnih števil while n > 0: stevka = n % 10 # števke gledamo od zadaj (enice) if stevka >= k: # ali gre k vsoti vsota += stevka n //= 10 # odrežemo že pregledane enice return vsota
Sestavite funkcijo vsota_stevk_stevil_med(m, n)
, ki vrne vsoto števk
vseh števil med vključno m
in n
.
def vsota_stevk_stevil_med(m, n): '''Vsota števk vseh števil med m in n''' vsota = 0 stevilo = m while stevilo <= n: vsota += vsota_stevk(stevilo, 0) # uporabimo funkcijo prejšnje naloge stevilo += 1 return vsota
Sestavite funkcijo najmanjse_stevilo_z_vsoto_stevk(n)
, ki izračuna
točno to, kar piše v njenem imenu.
def najmanjse_stevilo_z_vsoto_stevk(n): '''Vrne najmanjše število z vsoto števk n''' # matematični premislek pove, da se bno število končalo z največ možnimi 9kami # spredaj pa, kar še ostane. In če temu prištejemo 1, dobimo zapis števila (ki mu potem odštejemo 1) return (n % 9 + 1) * 10 ** (n // 9) - 1 # # če pa je zadeva videti preveč "zavita", lahko isto idejo udejanimo # tudi takole: # # koliko9 = n // 9 # koliko 9 potrebujemo # stev = str(n % 9) + '9' * koliko9 # return int(stev)
V restavraciji morajo nahraniti veliko lačnih ust, zato vsak dan naročijo nekaj hrane. Ker želijo varčevati, obdržijo nekaj hrane iz zaloge, nekaj pa jo naročijo na novo.
Sestavite funkcijo kolikoHrane1(potrebujemo, zaloga)
, ki vrne količino
hrane, ki jo je potrebno dokupiti. V spremenljivki potrebujemo
je
zapisana količina potrebne hrane, v spremenljivki zaloga
pa količina
hrane na zalogi. Če hrane ni potrebno dokupiti, naj funkcija vrne
število 0. Predpostavite lahko, da sta oba argumenta nenegativni celi števili.
Primer:
>>> kolikoHrane1(15, 5)
10
def kolikoHrane1(potrebujemo, zaloga): '''Koliko hrane je potrebno nakupiti''' if potrebujemo > zaloga: return potrebujemo - zaloga else: return 0 # lahko bi napisali tudi brez else, # (seveda je return 0 potem ustrezno zamaknjen v levo! # saj return pri if tako ali tako zaključi program! # lahko pa rešitev skrčimo le v stavek # return max(potrebujemo - zaloga, 0)
Zgornja metoda se ni najbolje obnesla, saj ni prav nič upoštevala, kakšno hrano restavracija potrebuje. Zato so hrano razdelili v tri osnovne kategorije. Imenujmo jih hrana tipa 1, tipa 2 in tipa 3.
Sestavite funkcijo kolikoHrane2(potrebujemo1, potrebujemo2, potrebujemo3, zaloga1, zaloga2, zaloga3)
, ki sprejme šest
nenegativnih celih števil. V potrebujemoX
je zapisana količina potrebne hrane tipa zalogaX
pa zaloga hrane
tipa
Funkcija naj vrne tri cela števila (kot return a, b, c
- seveda namesto
a
, b
, c
uporabimo smiselne spremenljivke). Število na
Primer:
>>> kolikoHrane2(10,12,7, 12, 8, 5)
0, 4, 2
def kolikoHrane2(potrebujemo1, potrebujemo2, potrebujemo3, zaloga1, zaloga2, zaloga3): '''koliko hrane posameznega tipa je potrebno kupiti''' potrebnaHranaTip1 = kolikoHrane1(potrebujemo1, zaloga1) # brez funkcije kolikoHrane1 bi pač napisali # potrebnaHranaTip1 = max(potrebujemo1 - zaloga1, 0) potrebnaHranaTip2 = kolikoHrane1(potrebujemo2, zaloga2) potrebnaHranaTip3 = kolikoHrane1(potrebujemo3, zaloga3) if max(potrebnaHranaTip1, potrebnaHranaTip2, potrebnaHranaTip3) == 0: return 0 return potrebnaHranaTip1, potrebnaHranaTip2, potrebnaHranaTip3
Zgornja metoda je požela velik uspeh, a še vedno je najbolj priljubljene hrane včasih zmanjkalo. Zato so se odločili, da bodo najbolj priljubljeno hrane naročili nekaj več, kot bi bilo nujno potrebno.
Sestavite funkcijo kolikoHrane3
, ki se obnaša enako kot funkcija
kolikoHrane1
, le da:
Primer:
>>> kolikoHrane3(15, 5)
20
def kolikoHrane3(potrebujemo, zaloga): '''Koliko hrane je potrebno kupiti, če kupimo nekaj na zalogo''' if zaloga < potrebujemo/4: return (potrebujemo - zaloga) * 3 elif zaloga < potrebujemo/2: return (potrebujemo - zaloga) * 2 elif zaloga < potrebujemo: return potrebujemo - zaloga else: return 0
Miha se rad igra igro ugibanja števil. V ta namen bi rad napisal računalniški
program, ki bi mu izžrebal število, on pa bi ga ugibal. V pomoč mu sestavite
funkcijo relacija(racunalnik, miha)
, ki sprejme dve celi števili. Funkcija
naj vrne niz 'premalo'
, če je število miha
manjše od števila racunalnik
;
niz 'preveč'
, če je število miha
večje od števila racunalnik
in niz
'Bravo!'
, če sta števili enaki.
Primer:
>>> relacija(45, 20)
'premalo'
def relacija(racunalnik, miha): '''je miha povedal premalo, preveč ali točno''' if racunalnik > miha: return 'premalo' if racunalnik < miha: return 'preveč' return 'Bravo!'
Mihu je ugibanje v eni dimenziji počasi postalo predolgočasno. Zato je začel
ugibati števila, ki ležijo na celoštevilski mreži v ravnini. V ta namen
sestavite funkcijo ugibaj(racunalnikX, racunalnikY, mihaX, mihaY)
, ki sprejme seznama
dveh celih števil (točk v ravnini).
Vrne naj niz 'Od prave točke si oddaljen vsaj {0}.'
, če Miha točke ni
uganil in niz 'Bravo!'
, če je Miha točko uganil. Pri tem naj bo namesto
{0}
izpisana Evklidska razdalja med točkama miha
in racunalnik
,
zaokrožena navzdol na najbližje celo število.
Primer:
>>> ugibaj(15, 15, 16, 16)
'Od prave točke si oddaljen vsaj 1.'
def ugibaj(racunalnikX, racunalnikY, mihaX, mihaY): '''Kako daleč od točke smo''' razdalja = int(((racunalnikX - mihaX)**2 + (racunalnikY - mihaY)**2)**0.5) if razdalja == 0: return 'Bravo!' else: return 'Od prave točke si oddaljen vsaj ' + str(razdalja) + '.'
Miha se je tudi igre v dveh dimenzijah hitro naveličal, saj je trajala predolgo. Zato si je poleg oddaljenosti od izžrebane točke zaželel vedeti še, kje leži njegova točka glede na izžrebano število: v prvem, drugem, tretjem ali četrtem kvadrantu.
Pri tem k prvemu kvadrantu štejemo tudi pozitivno
Sestavite funkcijo ugibaj1(racunalnikX, racunalnikY, mihaX, mihaY)
, ki naj vrne niz 'Bravo!'
,
če je Miha točko uganil oz. niz 'Tvoja točka je v {0}. kvadrantu.'
(kjer na
na namesto {0}
izpisana številska oznaka kvadranta).
Primer:
>>> ugibaj1(15, 15, 16, 16)
'Tvoja točka je v 1. kvadrantu.'
>>> ugibaj1(15, 15, 14, 14)
'Tvoja točka je v 3. kvadrantu.'
def ugibaj1(racunalnikX, racunalnikY, mihaX, mihaY): '''Ugibanje točke z vrnjenim kvadrantom''' razdalja = int(((racunalnikX - mihaX)**2 + (racunalnikY - mihaY)**2)**0.5) if razdalja == 0: odg = 'Bravo!' else: kvadrant = 0 if mihaX > racunalnikX and mihaY >= racunalnikY: kvadrant = 1 elif mihaX >= racunalnikX and mihaY < racunalnikY: kvadrant = 4 elif mihaX <= racunalnikX and mihaY > racunalnikY: kvadrant = 2 elif mihaX < racunalnikX and mihaY <= racunalnikY: kvadrant = 3 odg = 'Tvoja točka je v ' + str(kvadrant) + '. kvadrantu.' return odg
Kamion z nosilnostjo 10 ton porabi 30 litrov dizla na prevoženih 100 km.
Naročniku, ki je od skladišča oddaljen d
km, je treba pripeljati teza
ton peska. Kamion ima trenutno v rezervoarju gorivo
litrov dizla.
Ali bo kamion uspešno opravil pot? Če je teža tovora večja od nosilnosti, naj program izpiše
Tovor je pretežak. Kamion ne sme na pot!
Če bo na poti zmanjkalo goriva (nikjer ob poti ni bencinske črpalke), naj program izpiše
Po prevoženih x kilometrih bo zmanjkalo goriva.
kjer je namesto x
treba izpisati opravljeno razdaljo, ki naj bo
zaokrožena navzdol (na celo število). Sicer naj program izpiše
Kamion bo uspešno dostavil tovor naročniku.
Kako bo kamion prišel nazaj do skladišča, naj vas ne skrbi. Predpostavite še, da teža tovora ne vpliva na porabo goriva. Primer:
Koliko km: 354
Koliko je teža peska: 7.5
Koliko goriva je v rezervoarju: 151.4
Kamion bo uspešno dostavil tovor naročniku.
d = int(input("Koliko km: ")) teza = float(input("Koliko je teža peska: ")) gorivo = float(input("Koliko goriva je v rezervoarju: ")) x = 100 * gorivo / 30 if teza > 10: print('Tovor je pretežak. Kamion ne sme na pot!') elif x < d: print('Po prevoženih', int(x), 'kilometrih bo zmanjkalo goriva.') else: print('Kamion bo uspešno dostavil tovor naročniku.')
Posplošeno Fibonaccijevo zaporedje ostankov je definirano podobno kot
običajno Fibonaccijevo zaporedje , le da si prva dva člena lahko izberemo
sami, vse vsote pa računamo po modulu
V nalogi lahko predpostavite, da velja naslednjiČlen(a, b, n)
, ki pri podanih
zaporednih členih a
in b
izračuna naslednji člen.
def naslednjiČlen(a, b, n):
'''Vrne naslednji člen Fibbonacijevega zaporedja ostankov'''
return (a + b) % n
Če računamo nekaj zaporednih členov za začetna člena 0, 1 in za modul 2, dobimo zaporedje 0, 1, 1, 0, 1, 1, 0, 1, 1 ... Zaporedje ima torej periodo 3. Pri podatkih 0, 1, in 5 pa je zaporedje 0, 1, 1, 2, 3, 0, 3, 3, 1, 4, 0, 4, 4, 3, 2, 0, 2, 2, 4, 1, 0, 1, 1, 2, 3, .. perioda torej kar 20!
Funkcija perioda(a, b, n)
kot argumente dobi prva dva
člena zaporedja in število n
ter naj bi vrnila dolžino periode tega zaporedja.
Predpostavite, da velja
def perioda(a, b, n):
'''Dolžina periode FZO z začetnima členoma a in b in operacijo po modulu n
x = a
y = naslednjiČlen(a, b, n)
dopPer = 1
while x != a and y != b:
x, y = y, naslednjiČlen(x, y, n)
dolPer = 1
return dolPer
Vemo, da so v zgornji kodi štiri napakice in sicer v vrsticah 2, 3, 6 in 8. Popravi jih!
def naslednjiČlen(a, b, n): '''Vrne naslednji člen Fibbonacijevega zaporedja ostankov''' return (a + b) % n def perioda(a, b, n): '''Dolžina periode FZO z začenima členoma a in b in operacijo po modulu n''' x = b y = naslednjiČlen(a, b, n) dolPer = 1 while not(x == a and y == b): # dokler se člena ne ponovita - morda je to bolj jasno! x, y = y, naslednjiČlen(x, y, n) dolPer += 1 return dolPer
Oglej si funkcijo
def fun1(a, b, n, m):
'''Vrnem nekaj v povezavi s FZO z začetnima členoma a in b in operacijo po modulu n'''
x = min(a, b)
q = a
w = b
st = 2
while st <= m:
y = naslednjiČlen(q, w, n)
if y < x:
x = y
q = w
w = y
st += 1
return x
S pomočjo te funkcije sestavi funkcijo minMax(a, b, n, m)
, ki vrne najmanjši in največji člen med prvimi
m
členi FZO z začetnima členoma a
in b
, če se operacije izvajajo po modulu n
.
>>>minMax(0, 1, 5, 8)
(0, 3)
>>>minMax(1, 1, 5, 4)
(1, 3)
Namig: Poskušaj razumeti, kaj dana funkcija počne.
Spremenljivkam daj smiselna imena. Npr. za y
je očitno, da gre za člen v FZ.
Tudi q
in w
imate nekaj zveze s tem. Čemu pa služi x
?
def minMax(a, b, n, m): '''Vrnem najmanjši in največji člen med prvimi m členi FZO z začetnima členoma a in b in operacijo po modulu n''' if m == 1: return (a, a) najmanj = min(a, b) največ = max(a, b) predzadnji = a zadnji = b st = 3 while st <= m: naslednji = naslednjiČlen(predzadnji, zadnji, n) if naslednji < najmanj: # našli smo manjšega najmanj = naslednji if naslednji > največ: # našli smo večjega največ = naslednji predzadnji, zadnji = zadnji, naslednji st += 1 return (najmanj, največ)
Sestavite funkcijo najkrajšaPerioda(a, b, m, n)
, ki vrne najmanjši
tak (a, b, i)
minimizira dolžino periode iz prve podnaloge. Predpostavite lahko,
da sta argumenta m
in n
naravni števili in velja
>>> najkrajsa_perioda(2, 2, 6, 19)
8
Namig: Iz 1. podnaloge znamo izračunati dolžino periode.
Ta podnaloga pa bi rada samo najkrajšo periodo med vsemi FZO
z začetnima členoma a
in b
, če za modul jemljemo n, n+1, n+2, .., m
def najkrajšaPerioda(a, b, m, n): '''Določi pri katerem modulu m <= modul <= n ima FZO najkrajšo periodo''' minPer = m # kandidat za modul za najkrajšo periodo dolMinPer = perioda(a, b, m) # dolžina te minimalne periode modul = m + 1 while modul <= n: # pregledamo še ostale kandidate dolPer = perioda(a, b, modul) if dolPer < dolMinPer: # smo našli krajšo? minPer = modul dolMinPer = dolPer modul += 1 return minPer
Sestavite funkcijo vsotaDeliteljev(n)
, ki bo izračunala vsoto vseh
pravih deliteljev števila n
. Pravi delitelji so vsi delitelji, razen
števila samega, torej tudi 1 (hm, kaj pa za 1? - recimo, da je najbolj logično, da je za 1
vsota pravih deliteljev 0).
>>> vsotaDeliteljev(24)
36
def vsotaDeliteljev(n): '''Vrne vsoto pravih deliteljev števila n''' delitelj = 1 vsota = 0 while delitelj < n: if n % delitelj == 0: vsota += delitelj delitelj += 1 return vsota ## Lahko pa tudi upoštevamo, da delitelji števila vedno nastopajo v parih. ## def vsotaDeliteljev(n): ## vsota = 1 ## d = 2 ## while d * d < n: # gremo do korena iz n ## if n % d == 0: ## vsota += d ## vsota += n // d # še drugi element para ## d += 1 ## if d * d == n: # če je n slučajno popoln kvadrat ## vsota += d ## return vsota
Števili a
in b
sta prijateljski, če je vsota pravih deliteljev
števila a
enaka številu b
, vsota pravih deliteljev števila b
pa številu a
. Sestavite program, ki premere m
in n
in
izpiše vse takšne pare (a, b)
prijateljskih števil, kjer je
>>>
Spodnja meja: 1000
Zgornja meja: 3000
(1184, 1210)
(2620, 2924)
Pari naj bodo izpisani naraščajoče glede na a
.
Par izpišemo s print((a, b))
.
def vsotaDeliteljev(n): '''Vrne vsoto pravih deliteljev števila n''' delitelj = 1 vsota = 0 while delitelj < n: if n % delitelj == 0: vsota += delitelj delitelj += 1 return vsota m = int(input('Spodnja meja: ')) n = int(input('Zgornja meja: ')) a = m while a <= n: # pregledamo vse možne a-je b = vsotaDeliteljev(a) vsotaB = vsotaDeliteljev(b) # ali je par ustrezen (b je že enak vs.del. a) if a < b <= n and a == vsotaB: print((a, b)) a += 1
Sestavite funkcijo najblizji_prijateljski_par(m, n)
, ki poišče in
vrne tisti par (a, b)
prijateljskih števil, da je (None, None)
.
>>> najblizji_prijateljski_par(1000, 3000)
(1184, 1210)
def najblizji_prijateljski_par(m, n): '''Najbližji prijateljski števili med m in n''' ma = mb = None # z ma in mb bomo označili naj par a = m while a < n: b = vsotaDeliteljev(a) if a < b <= n and vsotaDeliteljev(b) == a: if ma == None or b - a < mb - ma: # če smo našli boljši par (ali sploh prvega) ma, mb = a, b a += 1 return ma, mb
Sestavite funkcijo nepopolnost(n)
, ki vrne absolutno razliko med
številom n
in vsoto vseh njegovih pravih deliteljev.
def nepopolnost(n): '''Razlika med številom in vsoto njegovih deliteljev''' return abs(n - vsotaDeliteljev(n))
Število je popolnoma nepopolno, kadar je njegova nepopolnost večja od njega samega.
Sestavite funkcijo popolnomaNepopolno(n)
, ki vrne prvo popolnoma
nepopolno število, večje ali enako n
.
def popolnomaNepopolno(n): '''Vrne prvo popolnomaNepopolno število, večje ali enako n''' while(nepopolnost(n) <= n): n += 1 return n
Premisli, kaj počne spodaj navedena funkcija. Žal je rezultat domače naloge študenta 1. letnika, ki še ne ve, da funkcija brez komentarjev ni preveč ...
def funk(seznam):
j = 0
i = 0
d = len(seznam)
while i < d:
if seznam[i] == 1:
j += 1
i += 2
return j
Predelaj jo (kar pomeni tudi, da jo opremiš s komentarji, ustrezno popraviš
imena spremenljivk ...) v funkcijo prestej(n, seznam)
, ki v seznamu števil prešteje
kolikokrat se v tem seznamu pojavi število n
Na primer:
>>> prestej(5,[2, 5, 12, 3, 5, 3, 12, 8, 12])
2
def prestej(n, seznam): '''kolikokrat v seznamu nastopa n''' vseh = 0 # na začetku je vseh 0 i = 0 dolSez = len(seznam) while i < dolSez: # potujemo po vseh indeksih seznama if seznam[i] == n: vseh += 1 # če je enak, povečamo št. vseh i += 1 return vseh # vrne koliko je bilo vseh parametrov n
Napiši funkcijo prestejSodeLihe(seznam)
, ki v seznamu števil prešteje
kolikokrat se v tem seznamu pojavi sodo število. Rezultat naj vrne v obliki para (soda, liha)
Na primer:
>>> prestej([2, 5, 12, 3, 5, 3, 12, 8, 12])
(5, 4)
def prestejSodaLiha(n, seznam): '''koliko je v seznamu sodih in lihih''' sodih = 0 # na začetku je vseh sodih 0 i = 0 dolSez = len(seznam) while i < dolSez : # potujemo po vseh indeksih seznama if seznam[i] % 2 == 0: sodih += 1 # če je sodo i += 1 return (sodih, dolSez - sodih) # tako bo hitreje, kot če bi posebej šteli še lihe
Funkcija seznamMest(n,seznam)
def seznamMest(n, seznam):
'''indeksi, kje se v seznamu pojavi n '''
i = 1
while i <= len(seznam): # potujemo po vseh indeksih seznama
if seznam[i] == n: # primerjamo ali je i-ti elt. enak n
mesta.append([i]) # če pridemo do tega mesta, indeks dodamo k novemu seznamu
i = i + 1
return mesta # vrne nam seznam indeksov
vrnila seznam vseh mest, na katerih se v seznamu števil pojavi
število n
. Mesta štejemo od 0 dalje! Na primer:
>>> seznamMest(12,[2, 5, 12, 3, 5, 3, 12, 8, 12])
[2, 6, 8]
Žal ne dela prav. Ima sintaktične in semantične napake. Popravi jo!
def seznamMest(n, seznam): '''indeksi, kje se v seznamu pojavi n ''' mesta = [] i = 0 while i < len(seznam): # potujemo po vseh indeksih seznama if seznam[i] == n: # primerjamo ali je i-ti elt. enak n mesta.append(i) # če pridemo do tega mesta, indeks dodamo k novemu seznamu i += 1 return mesta # vrne nam seznam indeksov
Funkcija kolikoEnic(seznamCelih)
naj vrne seznam, kjer na mestu i
povemo,
koliko je v
seznamu seznamCelih
števil, ki imajo kot enice vrednost i
.
Na primer:
>>> kolikoEnic([1432, 32155, 12, 351, 12353, 1255, 2313, 12, 8, 112])
[0, 1, 4, 2, 0, 2, 0, 0, 1, 0]
saj v seznamu števil ni nobenega števila, ki bi imelo na mestu enic 0, je eno število (namreč 351), ki ima na mestu enic 1, 4 števila (1432, 12, 12 in 112), ki imajo na mestu enic 2 ....
def kolikoEnic(seznamCelih): '''Preštejemo, koliko števil ima i enic''' števciEnic = [0] * 10 # vse možne enice i = 0 while i < len(seznamCelih): # potujemo po vseh indeksih seznama število = abs(seznamCelih[i]) števciEnic[število % 10] += 1 # povećčamo ustrezni števec i += 1 return števciEnic
Kot veste, je vektor v n razsežnem prostoru podan kot n-terka števil. Pojem dolžine lahko posplošimo in dobimo normo vektorja.
Najprej sestavimo funkcijo, ki izračuna "klasično" dolžino vektorja, torej njegovo Evklidsko normo.
>>> dolzinaVektorja([1, 1])
1.41421356237
>>> dolzinaVektorja([1, 4, 2, -5])
6.78232998313
def dolzinaVektorja(vektor): ''' vrne dolžino vektorja v n-razsežnem prostoru ''' vsotaKvadratov = 0 i = 0 while i < len(vektor): x = vektor[i] vsotaKvadratov += x**2 i += 1 return vsotaKvadratov**0.5
Sedaj pa sestavite funkcijo manhattanskaRazdalja(vektor)
, ki izračuna
dolžino vektorja, podanega z geometrijo (ameriških) mestnih taksijev,
oziroma njegovo prvo normo.
>>> manhattanskaRazdalja([1, 1])
2
>>> manhattanskaRazdalja([1, 4, 2, -5])
12
def manhattanskaRazdalja(vektor): ''' vrne prvo normo vektorja v n-razsežnem prostoru ''' vsota = 0 i = 0 while i < len(vektor): x = vektor[i] vsota += abs(x) i += 1 return vsota
Zanimiva je tudi uniformna norma ali razdalja Čebiševa (tudi neskončna norma).
Sestavi funkcijo neskoncnaNorma(vektor)
, ki izračuna to normo.
>>> neskoncnaNorma([1, 1])
1
>>> neskoncnaNorma([1, 4, 2, -5])
5
def neskoncnaNorma(vektor): ''' vrne neskončno normo vektorja v n-razsežnem prostoru ''' naj = abs(vektor[0]) # poiskati moramo navječjo abs. vrednost komponente i = 1 while i < len(vektor): x = abs(vektor[i]) if x > naj: # našli smo boljšo naj = x i += 1 return naj
V laboratoriju FMF-P1 jim je uspel tehnološki presežek. Sestavili so robota, ki zlahka hodi po stopnicah. Konkurenca na vsak način poskuša diskreditirati ta dosežek. Zato sestavljajo različne čudne kombinacije stopnic in čakajo, kdaj bo robot pri hoji padel, saj robot lahko prehodi le stopnico, ki je nižja od 20 cm. Ampak spretni študenti praktiki so robota opremili z merilnim sistemom, ki zmeri višino posamezne stopnice in napisali funkcijo (opaziš, da je lepo skrbno komentirana, kot vsa koda, ki jo pišejo v tem laboratoriju).
def kolikoStopnic(stopnice):
'''Koliko stopnic lahko prehodi robot'''
katera = 0 # indeks stopnice
while katera < len(stopnice):
v = stopnice[katera] # za vsako stopnico vzamemo njeno visino
if v > 20: # ce je visina stopnice na vrsti previsoka
return katera # koliko stopnic lahko prehodim (ker začnemo z 0, bo OK!)
katera += 1 # naslednja stopnica
# prehodili smo vse !
return len(stopnice)
Na osnovi te kode sestavi funkcijo kakoVisokoPridem(stopnice)
, ki kot
argument prejme seznam višin stopnic stopnice
rezultat, ki ga vrne, pa pove,
na kakšni višini bo robot po koncu hoje.
def kakoVisokoPridem(stopnice): '''kako visoko lahko lahko pride robot''' trenutnaVišina = 0 # zacnemo na visini 0 katera = 0 # indeks stopnice while katera < len(stopnice): v = stopnice[katera] # za vsako stopnico vzamemo njeno visino if v > 20: # ce je visina stopnice na vrsti previsoka return trenutnaVišina # do sem sem prišel ... trenutnaVišina += v # stopimo višje! katera += 1 # naslednja stopnica # prehodili smo vse ! return trenutnaVišina
Na FRI-P1 pa jim je uspelo izdelati napravo, ki zmoti merilni sistem robota tako, da meri
višine stopnic, merjene od tal (ne od prejšnje stopnice). Ampak praktiki s FMF se ne dajo.
Poleg tega, da robota izpopolnijo, da ima sedaj nastavljivo maksimalno višino koraka
(a žal se ta med hojo ne da spreminjati), na osnovi prejšnje naloge napišejo funkcijo
kakoVisoko(stopnice, korakRobota)
, ki kot
argument prejme seznam višin stopnic stopnice
, merjenih na "FRI način" in kako visoko
se lahko robot premakne
v enem koraku, rezultat, ki ga vrne, pa spet pove, kako visoko bo robot
priplezal.
Primer:
>>> kakoVisoko([5, 25, 45, 50, 76, 80, 81], 20)
50
def kakoVisoko(stopnice, korakRobota): '''Kako visoko bo pripezal robot''' trenutnaVišina = 0 # zacnemo na visini 0 katera = 0 while katera < len(stopnice): # za vsako stopnico vzamemo njeno visino (od tal) v = stopnice[katera] # kako visoko mora robot priti if v - trenutnaVišina <= korakRobota: # ce je visina stopnice na vrsti manjša od korakRobota trenutnaVišina = v # potem robot lahko stopi else: break # sicer ne preverjamo naprej in koncamo zanko katera += 1 # naslednja stopnica return trenutnaVišina
Brez (pa ne zgoraj, ampak spredaj in zadaj) Napiši
funkcijo brez(nekNiz)
, ki sestavi nov niz, pri katerem spustimo prvi in
zadnji znak niza nekNiz
.
def brez(niz): '''sestavi nov niz, pri katerem spustimo prvi in zadnji znak niza''' novNiz = '' ind = 1 while ind < len(niz) - 1: # spustimo prvega in zadnjega novNiz += niz[ind] ind += 1 return novNiz
Brezštevno Napiši
funkcijo brezŠtevk(nekNiz)
, ki sestavi nov niz, pri katerem spustimo vse števke, ki nastopajo
v nizu nekNiz
. Ali je v spremenljivki nekZnak
števka, lahko preverimo z
if '0' <= nekZnak <= '9': # v nekZnak je števka
def brezŠtevk(niz): '''sestavi nov niz, pri katerem spustimo števke''' novNiz = '' ind = 0 while ind < len(niz): nekZnak = niz[ind] if not('0' <= nekZnak <= '9'): # v nekZnak ni števka novNiz += nekZnak # dodamo k novemu nizu ind += 1 return novNiz
Brez sredine Napiši
funkcijo brezSredine(nekNiz)
, ki nizu spusti srednji znak. Če pa je niz sode dolžine, naj
ohrani vse znake
>>>brezSredine('matematika')
matematika
>>>brezSredine('fizik')
fiik
def brezSredine(niz): '''V nizu spusti srednji (ali srednja dva) znaka''' dolNiza = len(niz) if dolNiza % 2 == 0: # niz je sode dolžine return niz # niz je lihe dolžine novNiz = '' ind = 0 # prepišemo prvo polovico while ind < dolNiza // 2: nekZnak = niz[ind] novNiz += nekZnak # dodamo k novemu nizu ind += 1 # in še drugo ind += 1 while ind < dolNiza: nekZnak = niz[ind] novNiz += nekZnak # dodamo k novemu nizu ind += 1 return novNiz
Nekoč je živela ptica Črkojedka, ki je imela še posebej rada samoglasnike.
Še posebej od takrat, ko se je naučila, da v Pythonu lahko preverimo,
ali je nek znak samogaslnik s pomočjo operatorja in
>>>'a' in 'aeiouAEIOU'
True
>>>'t' in 'aeiouAEIOU'
False
Kadar je pojedla samoglasnik, je na tistem mestu pustila *.
Sestavi funkcijo crkojedka(niz)
, ki bo za dani niz vrnila nov niz z *
na mestu, kjer je bil samoglasnik.
Na primer:
>>>crkojedka('beseda')
b*s*d*
def crkojedka(niz): ''' funkcija v dani besedi samoglasnike zamenja z *''' samoglasniki ='aeiouAEIOU' novNiz='' i = 0 while i < len(niz): znak = niz[i] if znak in samoglasniki: # pogleda ali je posamezen znak v nizu samoglasnik # in če je, potem ga nadomesti z * novNiz += '*' else: # sicer ga le prepiše novNiz += znak i += 1 return novNiz
Določene besede so bile bolj kalorične (vsebovale več samoglasnikov), določene manj.
ker je Črkojedka na dijeti, ji sestavi funkcijo, ki ji bo pomagala izbirati
ustrezno hrano. Zato sestavi funkcijo crkojedkaHujša(niz)
, ki bo za dani niz vrnila
njegovo kalorično vrednost, torej število samoglasnikov
Na primer:
>>>crkojedkaHujša('črmlj')
0
>>>crkojedkaHujša('Kako debeeeeeeeeeeela sem!')
16
def crkojedkaHujša(niz): ''' funkcija prešteje samoglasnike *''' samoglasniki ='aeiouAEIOU' kaloričnaVrednost = 0 i = 0 while i < len(niz): znak = niz[i] if znak in samoglasniki: # pogleda ali je posamezen znak v nizu samoglasnik kaloričnaVrednost += 1 i += 1 return kaloričnaVrednost
Po neki precej "živahni" zabavi se je Črkojedka odmajala domov. Zjutraj se je
zbudila s hudim ... (hm, verjetno ne mačkom, kaj menite?). In opazila je,
da so se sedaj njene prehrambene navade spremenile. Sedaj ni več samoglasnikov
nadomeščala z *, ampak z ničemer več. Poleg tega pa se je vrstni red preostalih
znakov obrnil!
Sestavi funkcijo crkojedkaNePij(niz)
, ki vrne niz, kakor ga predela
Črkojedka z mačk... Na primer:
>>>crkojedkaNePij('beseda')
dsb
def crkojedkaNePij(niz): ''' funkcija v dani besedi izloči samoglasnike in obrne vrstni red znakov''' samoglasniki ='aeiouAEIOU' novNiz='' i = 0 while i < len(niz): znak = niz[i] if not znak in samoglasniki: # če znak ni samoglasnik novNiz = znak + novNiz # ga doda na konec i += 1 return novNiz
Skop vaj, pri katerih uporabljamo sezname
V Republiki Banana zaradi utrujenosti in pomanjkanja koncentracije kamionisti (pet minut za učenje slovenčine) vse pogosteje povzročajo nesreče. Na vladi so se odločili, da bodo sprejeli zakone, ki bodo uredili problematiko preutrujenih kamionistov. Najprej pa morajo analitiki preučiti njihove navade. V ta namen so pridobili podatke o kamionistih. Za vsakega imajo podan seznam, v katerem so shranjene prevožene razdalje po posameznih dnevih. Število 0 pomeni, da je kamionist tisti dan počival. Na primer seznam
[350, 542.5, 0, 602, 452.5, 590.5, 0, 248]
pomeni, da je kamionist prvi dan prevozil 350 km, drugi dan je prevozil 542.5 km, tretji dan je počival itd.
Sestavite funkcijo pocitekInPovprecje(voznja)
, ki kot argument
dobi zgoraj opisani seznam (prevožene razdalje po posameznih dnevih)
in vrne par števil. Prvo število naj bo število dni, ko je kamionist
počival. Drugo število naj bo na eno decimalko zaokrožena
povprečna dnevna prevožena razdalja, pri
čemer upoštevamo samo tiste dneve, ko ni počival. Predpostavite lahko,
da kamionist vsaj en dan ni počival. Primer:
>>> pocitekInPovprecje([200, 300, 0, 100])
(1, 200.0)
Kamionist je torej enkrat počival. Ob dnevih, ko ni počival, pa je v povprečju prevozil 200 km.
def pocitekInPovprecje(voznja): '''Vrne par števil. Prvo pove število dni, ko kamionist počiva in drugo povprečno št. kilometrov na dneve vožnje ''' stPocitkov = 0 delovnihDni = 0 skupnoKilometrov = 0 for prevozenoTaDan in voznja: if prevozenoTaDan == 0: stPocitkov += 1 else: delovnihDni += 1 skupnoKilometrov += prevozenoTaDan return stPocitkov, round(skupnoKilometrov / delovnihDni, 1) # zaradi predpostavke # zagotovo ne delimo z 0!
Napišite funkcijo primerjaj(prvi, drugi)
, ki primerja vožnjo dveh
kamionistov. Funkcija kot argumenta dobi dva enako dolga seznama
prvi
in drugi
, ki opisujeta vožnjo dveh kamionistov, ki sta se
podala na isto pot. Funkcije naj sestavi in vrne nov seznam, v katerem
je za vsak dan zapisano, kdo je do tega dne skupaj prevozil večjo razdaljo:
1
, če je bil to 1. kamionist; 2
, če je bil to 2. kamionist in
0
, če sta oba prevozila enako razdaljo. Primer:
>>> primerjaj([200, 300, 100], [200, 200, 300])
[0, 1, 2]
>>> primerjaj([500, 100, 100], [100, 200, 200])
[1, 1, 1]
def primerjaj(prvi, drugi): '''Vrne seznam podatkov o tem, kateri kamionist je prišel do določenega dne dlje''' prevozenoPrvi = 0 # skupno število prevoženih kilometrov do določenega dne prevozenoDrugi = 0 primerjava = [] dan = 0 while dan < len(prvi): # uporabimo while, ker potrebujemo podatke iz obeh seznamov prevozenoPrvi += prvi[dan] prevozenoDrugi += drugi[dan] # kdo je v tem trenutku že dlje if prevozenoPrvi > prevozenoDrugi: primerjava.append(1) elif prevozenoPrvi < prevozenoDrugi: primerjava.append(2) else: primerjava.append(0) dan += 1 return primerjava
Vlada je uzakonila naslednja pravila: Povprečna prevožena razdalja v treh zaporednih dneh ne sme biti več kot 500 km. (Štejemo tudi dneve, ko je kamionist počival.) Kamionist ne sme brez počitka voziti več kot 5 dni v zaporedju.
Ker pa so ugotovili, da so kamionisti prevečkrat svoje zaporedje skrajšali na dva dni in se s tem dejansko izognili pravilu, so uzakonili še: Zadnji dan ne sme voziti več kot 500 km. Povprečje zadnjih dveh dni ne sme biti več kot 500 km.
Sestavite funkcijo poPravilih(voznja)
, ki vrne True
, če se je
kamionist držal predpisov, in False
, če se jih ni.
>>> poPravilih([50, 200, 300, 20, 100, 60])
False
>>> poPravilih([600, 200, 0, 300, 300, 0, 600, 600, 400])
False
>>> poPravilih([600, 600, 0, 600, 600])
False
>>> poPravilih([600, 600, 0, 200, 600])
False
def poPravilih(voznja): '''Ali je vožnja potekala po pravilih''' zaporedno = 0 dan = 0 while dan < len(voznja) - 2: # za račun povprečja zaporedja! prevozil = voznja[dan] if prevozil == 0: # je počival, začnemo šteti od začetka zaporedno = 0 else: zaporedno += 1 if zaporedno > 5: # zaporedoma vozi več kot 5 dni return False povprecje = (voznja[dan] + voznja[dan+1] + voznja[dan+2]) / 3 if povprecje > 500: return False dan += 1 # pregledamo še zadnja dva dni while dan < len(voznja): # dan je že ustrezno "velik", torej se bo zanka izvedla 2krat prevozil = voznja[dan] if prevozil == 0: zaporedno = 0 else: zaporedno += 1 if zaporedno > 5: return False dan += 1 # še povprečji # če imamo sploh še 2 dni (če imamo le en podatek+, to ne bo res) if len(voznja) - dan == 2: if (voznja[len(voznja) - 1] + voznja[len(voznja) - 2])/2 > 500: return False # še kontrola dolžine vožnje zadnji dan if voznja[-1] > 500: return False # uspešno preko vseh kontrol return True
Podatke za več kamionistov so analitiki združili v en sam seznam. Zgled takega seznama:
vsiSkupaj = [
[50, 200, 300, 20, 100, 60],
[600, 600, 0, 600, 600, 0, 500, 500],
[600, 200, 0, 300, 300, 0, 600, 600, 400]
]
Sestavite funkcijo preveriVse(seznamVozenj)
, ki dobi kot argument
na tak način opisan seznam in vrne seznam logičnih vrednosti, ki za vsakega kamionista
pove, če je vozil po predpisih. Primer:
>>> preveriVse(vsiSkupaj)
[False, True, False]
def preveriVse(seznamVozenj): '''Preveri vožnje vseh kamionistov''' rezultat = [] for voznjaPosameznika in seznamVozenj: # rezultat.append(poPravilih(voznjaPosameznika)) return rezultat
Ko so vožnje vseh kamionistov že tako lepo združene, so se analitiki spravili
računati še to, kakšno je navečje število voženj, ki jih je nekdo opravil,
kakšno je največje število dni počitka in kakšno največje in kakšno najmanjše povprečno
povprečno število dnevno prevoženih kilometrov (povprečje tako, kot pri prvi
nalogi - štejemo le dneve vožnje). Pri tem upoštevamo samo tiste kamioniste,
ki so vozili po pravilih!
Sestavite funkcijo analitika(seznamVozenj)
, ki dobi kot argument
opisani seznam in vrne nabor 4 vrednosti: največ voženj, največ dni počitka, maksimalno dnevno prevoženih
in minimalno dnevno prevoženih km. Predpostavi, da imamo vsaj enega kamionista, ki je vozil po predpisih!
Primer (podatki iz prejšnje naloge):
>>> analitika(vsiSkupaj)
(6, 2, 566.7, 566.7)
def analitika(seznamVozenj): '''med pravilno vozečimi kamionisti poišče nabor 4 vrednosti: največ voženj, največ dni počitka, maksimalno dnevno prevoženih in minimalno dnevno prevoženih km.''' minPovp = 600 # vsaj en bo vozil po predpisih, torej bo minimalno povprecje zagotovo pod 500! maxPovp = 0 maxPoc = 0 # maksimalno dni počitka maxVozenj = 0 for voznjaPosameznika in seznamVozenj: if poPravilih(voznjaPosameznika): # "dobri" voznik, ga upoštevamo poc, povp = pocitekInPovprecje(voznjaPosameznika) vozenj = len(voznjaPosameznika) - poc # ali so katere od teh vrednosti za "naj" if poc > maxPoc: maxPoc = poc # namesto if, uporabimo raje kar min, oz. max maxVozenj = max(vozenj, maxVozenj) minPovp = min(povp, minPovp) maxPovp = max(povp, maxPovp) return (maxVozenj, maxPoc, maxPovp, minPovp)
Na Najboljši TV je prava zmešnjava (kar za najnovejšo TV v Sloveniji niti ni tako nenavadno). Le še 5 minut do začetka oddaje Izbiramo najlepšega bika Slovenije. Težav pa cel kup.
Prva težava je, da je na vseh seznamih naveden napačni vrstni red imen bikov. Režiser na
vsak način poskuša prepričati voditeljski par, da ni nič narobe, le od spodaj navzgor
naj bereta razvrstitev. A kljub temu, da sta to daleč najbolj inteligentna TV voditelja
v Sloveniji, se bojita, da bo to zanju pretežka naloga.
Zato jim moraš hitro napisati
funkcijo obrniSeznamBikov(sezBik)
, ki vrnila nov seznam teh imen
v obratnem vrstnem redu. Za seznam
['Bukso', 'Hitri', 'Šeko', 'Lisko']
naj vrne seznam
['Lisko', 'Šeko', 'Hitri', 'Bukso']
Pazi, ker moraš vrniti nov seznam, uporabe metode reverse ne bo OK!
def obrniSeznamBikov(sezBik): ''' vrne nov seznam bikov v obratnem vrstnem redu ''' novSez = [] for bik in sezBik: novSez = [bik] + novSez # ker dodajamo spredaj, bomo seznam obrnili return novSez
Seznam bikov je sedaj urejen. A kaj, ko so na seznam prikradle tudi krave (na TV
sumijo, da gre za podtalno delovanje stricev iz ozadja, a ...). In zato se bodo
pritožili na MCSodišče. A ura je neizprosna, ustrezen seznam potrebujejo takoj.
Na srečo je najomiljeni voditelj z vso svojo avtoriteto ugotovil,
da je krave zlahka prepoznati, saj se vsa njihova imena končajo z 'a'.
Ker želijo ohraniti dokaze, morajo seznam s pomešanimi
kravami ohraniti. Zato sestavi
funkcijo odstraniKrave(seznam)
, ki vrnila nov seznam teh imen
brez krav. Biki morajo ohraniti svoj vrstni red. Za seznam
['Liska', 'Šeko', 'Hitri', 'Buksa']
funkcija vrne
['Šeko', 'Hitri']
def odstraniKrave(seznam): ''' vrne nov seznam brez krav (imen, ki se končajo z a) ''' novSez = [] for žival in seznam: if žival[-1] != 'a' : # ime se ne končna z a novSez.append(žival) return novSez
težav pa še ni konec. Vse to prekladanje seznamov je povzročilo, da so sedaj določena imena v seznamu
navedena večkrat. Zato napiši funkcijo odstraniOdvečne(seznam)
, ki vrne nov seznam, a tako, da
iz seznama pomeče
vsa odvečna imena. Pri enakih imenih ohrani le tistega, ki se je v seznamu
pojavil prvi.m Iz
['Lisko', 'Šeko', 'Šeko', 'Šeko', 'Hitri', 'Bukso', 'Lisko']
dobimo
['Lisko', 'Šeko', 'Hitri', 'Bukso']
Namig: Kaj naredi 'bla' in ['blu', 'ble', 'bla', 'blu']
?
def odstraniOdvečne(seznam): ''' vrne nov seznam brez odvečnih (podvojenih) imen ''' novSez = [] for žival in seznam: if žival not in novSez : # ime se še ni pojavilo novSez.append(žival) return novSez
Četa je najdaljše možno strnjeno podzaporedje v danem seznamu števil z določeno lastnostjo. Če je zaporedje naraščajoče (vsak naslednji element podzaporedja je večji), govorimo o naraščajočih četah, če je nepadajoče (torej je vsak naslednji element večji ali enak) o nepadajočih četah ...
Celoten seznam je tako sestavljen iz več zaporednih čet. Predpostavili bomo,
da bomo vedno upoštevali čete iste vrste. Tako v seznamu
[2,5,7,1,45,7,7,15]
najdemo kar 4 naraščajoče čete (2,5,7
, 1,45
, 7
in 7,15
),
seznam [3,5,8,10,12]
pa je sestavljen iz ene same čete.
Po drugi strani pa v seznamu
[2,5,7,1,45,7,7,15]
najdemo kar 6 padajočih čete (2
, 5
, 7, 1
, 45, 7
, 7
in 15
)
in 5 nenaraščajočih čet (2
, 5
, 7, 1
, 45, 7, 7
in 15
)
Sestavite funkcijo naraščajoč(seznam)
, ki preveri, ali elementi seznama
seznam
tvorijo narascajoče zaporedje.
>>> naraščajoč([])
True
>>> naraščajoč([1, 2, 5, 8, 12, 35])
True
>>> naraščajoč([3, 5, 5])
False
>>> naraščajoč([2, 6, 4, 8, 9, 6])
False
def naraščajoč(seznam): '''Ali vsi elementi seznama naraščajo''' if seznam == []: return True # na "prazno" res for i in range(1, len(seznam)): if seznam[i - 1] >= seznam[i]: return False return True # vse kontrole padanja so bile neuspešne, narašča!
Sestavi funkcijo številoNepadajočihČet(sez)
, ki v danem številskem seznamu prešteje, iz
koliko nepadajočih čet je sestavljen. Nepadajoča četa je najdaljši možen nepadajoče urejen
podseznam, ali še enostavneje, dokler se zaporedni elementi seznama
ne zmanjšujejo, so v isti četi.
>>> številoNepadajočihČet([])
0
>>> številoNepadajočihČet([6])
1
>>> številoNepadajočihČet([1, 3, 4, 7, 23, 56, 81])
1
>>> številoNepadajočihČet([1, 2, 2, 6, 2, 3, 7, 5, 2, 3, 8])
4
def številoNepadajočihČet(seznam): ''' koliko nepadajočih čet ima seznam ''' if seznam == []: return 0 stCet = 0 prejšni = seznam[0] # ker NE velja x < x ne bo težav z začetkom! for x in seznam: if x < prejšni: # konec čete, začetek nove stCet += 1 prejšni = x return stCet + 1 # 1 zaradi zadnje!
Sestavi funkcijo številoNaraščajočihČet(sez)
, ki v danem številskem seznamu prešteje,
iz koliko naraščajočih čet je
sestavljen. Naraščajoča četa je najdaljši možen naraščajoče urejen podseznam, ali še
enostavneje: dokler zaporedni elementi seznama naraščajo, so v isti četi.
>>> številoNaraščajočihČet([])
0
>>> številoNaraščajočihČet([6])
1
>>> številoNaraščajočihČet([1, 3, 4, 7, 23, 56, 81])
1
>>> številoNaraščajočihČet([1, 2, 2, 6, 2, 3, 7, 5, 2, 3, 8])
5
def številoNaraščajočihČet(seznam): ''' koliko naraščajočih čet ima seznam ''' if seznam == []: return 0 stCet = 0 prejšni = seznam[0] for x in seznam: if x <= prejšni: # konec čete, začetek nove stCet += 1 prejšni = x return stCet
Sestavite funkcijo dolžinaNajdaljšeNaraščajočeČete(seznam)
, ki ugotovi,
kakšna je dolžina najdaljše čete v seznamu seznam
.
>>> dolžinaNajdaljšeNaraščajočeČete([])
0
>>> dolžinaNajdaljšeNaraščajočeČete([2, 5, 7, 10])
4
>>> dolžinaNajdaljšeNaraščajočeČete([1, 3, 6, 3, 8, 8, 10, 12])
3
def dolžinaNajdaljšeNaraščajočeČete(seznam): '''Kako dolga je najdaljša naraščajoča četa''' if seznam == []: return 0 naj = 0 # največja dolžina do sedaj dolzina = 1 # dolžina trenutne čete (vsebuje prvi element) for i in range(1, len(seznam)): # od drugega elementa naprej if seznam[i - 1] < seznam[i]: dolzina += 1 # še vedno imamo isto četo else: # naleteli smo na novo četo if dolzina > naj: # je morda ravno zaključena četa daljša? naj = dolzina dolzina = 1 # začeli smo na novo return max(naj, dolzina) #paziti moramo še na dolžino zadnje
Sestavite funkcijo naraščajočeČete(seznam)
, ki vrne seznam vseh naraščajočih čet, ki tvorijo
seznam seznam
.
>>> naraščajočeČete([1, 3, 6, 3, 8, 8, 10, 12])
[[1, 3, 6], [3, 8], [8, 10, 12]]
def naraščajočeČete(seznam): '''Seznam vseh naraščajočih čet v seznamu''' if seznam == []: return [] seznamCet = [] ceta = [seznam[0]] # trenutna četa for i in range(1, len(seznam)): if seznam[i - 1] < seznam[i]: ceta.append(seznam[i]) # podaljšujemo obstoječo četo else: # zaključili smo s prejšnjo seznamCet.append(ceta) ceta = [seznam[i]] # in začeli novo seznamCet.append(ceta) # dodamo še zadnjo četo return seznamCet
Butalci vsako leto priredijo polžje dirke. Pomagajte jim pri organizaciji.
Tekmovalnega polža opišemo s tremi parametri: starostjo, težo in
velikostjo. Faktor njegove tekmovalne sposobnosti opisuje takšna formula:
Med vsemi polži želimo poiskati najboljšega. Napišite funkcijo
najboljsi(s)
, ki sprejme seznam opisov polžev (seznam trojčkov
[starost, teža, velikost]
) in vrne faktor za najboljšega polža,
spet na dve decimalni mesti natančno.
>>> najboljsi([[5, 6, 72], [4, 17, 77], [14, 21, 22], [17, 36, 64], [13, 29, 23]])
16.39
def sposobnost(s, t, v): '''Vrne sposobnost polža''' return round((s + (t/v)**2)**2,2) def najboljsi(polzi): '''Določi faktor sposobnosti najboljšega polža''' polz = polzi[0] # prvi polž najboljsiFaktor = sposobnost(polz[0], polz[1], polz[2]) # prvi je najboljši ;-) for polz in polzi: # prvega bomo sicer gledsali dvakrat, a kaj zato! kakoSposoben = sposobnost(polz[0], polz[1], polz[2]) if kakoSposoben < najboljsiFaktor: # našli smo boljšega najboljsiFaktor = kakoSposoben return najboljsiFaktor # Mimogrede: z nekaj znanja /ki ga še nimamo/ bi nalogo lahko rešili # v eni vrstici ;-) ##def najboljsi(s): ## return min([sposobnost(x[0], x[1], x[2]) for x in s])
Butalski polži se premikajo samo v štirih smereh: sever, jug, vzhod in
zahod, kar v koordinatnem sistemu pomeni gor, dol, desno in levo.
V vsakem koraku se premaknejo za eno enoto, lahko pa tudi mirujejo.
Njihove premike zato lahko opišemo s seznami, ki vsebujejo poljubno
zaporedje črk 'S'
, 'J'
, 'V'
, 'Z'
in 'M'
.
Napišite funkcijo pot(premiki)
, ki sprejme seznam, ki opisuje premike polža
in pove, kako daleč je polž lezel in kako daleč (zračne razdalje) je prilezel. Rezultat naj bo
dan v obliki para celo in dec. število, kjer je slednje zaokroženo na dve decimalni mesti.
>>> pot(['M', 'J', 'V', 'S', 'S', 'M'])
(4, 1.41)
def pot(premiki): '''Kako daleč je lezel in prilezel polž''' x=0 y=0 kolikoMirovanj = 0 for premik in premiki: # izračunamo končno točko, ter število mirovanj if premik == 'S': y += 1 elif premik == 'J': y -= 1 elif premik == 'V': x += 1 elif premik == 'Z': x -= 1 else: kolikoMirovanj += 1 kolikoLazenja = len(premiki) - kolikoMirovanj return (kolikoLazenja, round((x**2 + y**2)**0.5, 2))
Po končanem tekmovanju so znane poti vseh polžev. Velja, da je zmagovalec
tisti polž, ki je prilezel najdlje (seveda pa si lahko prvo mesto deli
več zmagovalcev, če so prelezli isto razdaljo). Pri tem seveda
doseženo razdaljo računamo zaokroženo, kot pri zg. nalogi!
Napišite funkcijo
zmagovalci(s)
, ki sprejme seznam poti vseh polžev ter izračuna, koliko
polžev je osvojilo prvo nagrado.
>>> zmagovalci([['S', 'Z', 'S'], ['M', 'Z', 'V'], ['J', 'J', 'Z'], ['J', 'J', 'Z'], ['S', 'S', 'M']])
3
def zmagovalci(poti): '''Koliko polžev je zmagalo''' najRazdalja = -1 # vse poti bodo daljše kolikoZmagovalcev = 0 for potPolza in poti: _, razdalja = pot(potPolza) # lazil nas načeloma ne zanima, zato "čudno" imen - le podčrtaj if razdalja > najRazdalja: # našli smo boljšega najRazdalja = razdalja kolikoZmagovalcev = 1 # začnemo šteti znova elif razdalja == najRazdalja: kolikoZmagovalcev += 1 # en več z naj razdaljo return kolikoZmagovalcev # # z nekaj dodatnega znanja je zapis rešitve krajši # ##def zmagovalci(s): ## p = [pot(x) for x in s] ## mx = max(p) ## return p.count(mx)
Mirko in Slavko sta postala navdušena nad vsemi oblikami števil, zaporedij in podobno.
Potem ko sta se naveličala preštevati, ali število zrn v krogih
pri sončnici res ustreza Fibonaccijevemu
zaporedju, sta naletela na funkcijo, ki naj bi vrnila seznam, ki vsebuje prvih
n
vrstic Pascalovega (binomskega) trikotnika
(vrstica naj bo spet seznam).
def trikotnik(n):
'''Vrne n vrstic Pascalovega trikotnika'''
celota = [[1]] # bo tole prav?
zgoraj = []
j = 0
while j <= n: # tu je nekaj narobe
i = 1
nova = [1]
while i < len(zgoraj):
nova = [zgoraj[i - 1] + zgoraj[i]] # hm, tole ...
i = i + 1
zgoraj = nova + [1]
celota = celota + zgoraj # tudi tukaj
j = j + 1
return celota
Žal (kot običajno) ima nekaj napak. Odpravi ji ... Na srečo je Mirko že intenzivno preiskušal funkcijo in odkril štiri možna mesta napak (glej oznake v kodi). Slavko pravi, da je Mirko pretiraval in da so napake zagotovo tri.
def trikotnik(n): '''Vrne n vrstic Pascalovega trikotnika''' celota = [[1]] # začetna vrstica zgoraj = [] # prejšnja vrstica j = 0 while j < n - 1: i = 1 nova = [1] # sestavimo novo vrstico while i < len(zgoraj): # na osnovi prejšnje sestavimo novo nova += [zgoraj[i - 1] + zgoraj[i]] # dodamo vsoto zgornjih členov i = i + 1 zgoraj = nova + [1] # še zaključna enka - in si jo zapomnimo za naslednji korak celota = celota + [zgoraj] # dodamo v trikotnik j = j + 1 return celota
Številka EMŠO je sestavljena iz trinajst števk v obliki DDMMLLL50NNNX, pri čemer je DDMMLLL rojstni datum, 50 je koda registra, NNN je zaporedna številka in X kontrolna številka. Trimestna številka, NNN, je med 000 in 499 za moške ter med 500 in 999 za ženske.
Napiši funkcijo je_zenska(emso)
, ki za številko EMŠO, ki jo podamo kot niz,
vrne True
, če pripada ženski in False
, če moškemu.
Primer:
>>> je_zenska('0505913509174')
True
>>> je_zenska('2109913502875')
False
def je_zenska(emso): '''Ali EMSO predstavlja žensko''' return emso[9] >= "5" # od 000 do 499 velja, da na 9. mestu stoji št. med 0 in 4 # od 500 do 999 velja, da na 9. mestu stoji št. med 5 in 9
Za okroglo mizo sedijo gosti. Nekateri so srečni, drugi ne. Konkretno: srečni so moški, ki sedijo med dvema ženskama in ženske, ki sedijo med dvema moškima. Razpored gostov podamo s seznamom njihovih številk EMŠO.
Napiši funkcijo stevilo_srecnezev(razpored)
, ki prejme takšen seznam in vrne število srečnih gostov.
Pazi: Ker je miza okrogla, sedi prvi gost poleg zadnjega. Če sedita moški in ženska sama za okroglo mizo, seveda nista srečneža.
Primer:
>>> stevilo_srecnezev(['0903912505707', '0110913506472', '2009956506012','1102946502619', '1902922506199', '2602930503913',
'0204940508783','1602960505003', '0207959502025', '0207962509545'])
4
>>> stevilo_srecnezev(['0702948501362', '1505987508785'])
0
def stevilo_srecnezev(razpored): '''Koliko moških sedi med dvema ženskama, oz. koliko žensk sedi med dvema moškima''' srecnih = 0 n = len(razpored) if n < 3: # če nimamo vsaj tri osebe, ni srečnih! return 0 for i in range(n): pred = razpored[i-1] # sedez pred i-tim sedezom tren = razpored[i] # i-ti sedez nasl = razpored[(i+1) % n] # sedez za i-tim sedezom if je_zenska(pred) != je_zenska(tren) != je_zenska(nasl): # ce je na sredini moski, mora srecnih += 1 # imeti levo in desno zensko in obratno return srecnih
Jeremija ves svoj prosti čas (torej ko ne spi, ko ne toži nad bolečinami, skratka kako minuto na dan) preživi kot moderator na nekem manj znanem forumu, ki ima kar lepo število registriranih uporabnikov, vendar večina med njimi piše same neumnosti. Med takimi je še posebno dejaven Tomaž Majer. Če se zdi Jeremiji objava žaljiva, jo nemudoma zbriše. Če objava na forumu ni žaljiva, ampak je le precej neumna, pa naredi naslednje: Vse samoglasnike odstrani iz besedila in jih (v enakem vrstnem redu) doda nazaj na konec. Na primer sporočilo:
Banana je najboljša! Izjemno dobra je tudi v kombinaciji z Nutelo!
postane
Bnn j njbljš! zjmn dbr j td v kmbncj z Ntl!aaaeaoaIeooaeuioiaiiueo
Takó besedilo postane težko berljivo in večina bralcev ga ignorira. Če pa se najde kdo, ki ga vsebina resnično zanima, lahko z nekaj truda razvozla vsebino sporočila.
Opisana transformacija besedila je znana pod imenom disemvoweling.
Napišite funkcijo prviSamoglasnik(niz)
, ki kot argument dobi niz niz
in vrne položaj (indeks) prvega samoglasnika v danem nizu. Če v nizu ni
samoglasnika, vrni -1
>>> prviSamoglasnik('Krščen matiček!')
4
def prviSamoglasnik(niz): '''vrne položaj (indeks) prvega samoglasnika v danem nizu''' samoglasniki = "aeiouAEIOU" kje = 0 for znak in niz: if znak in samoglasniki: # takoj pri prvem bomo zaključili zadevo return kje kje += 1 return -1 # ni ga bilo def prviSamoglasnikDieHardPython(niz): #dieHard Pythonovci bi seveda zadevo napisali takole samoglasniki = "aeiou" return min(niz.index(c) for c in samoglasniki + samoglasniki.upper() if c in niz)
Napišite funkcijo disemvowel(sporocilo)
, ki kot argument prejme niz
sporocilo
. Funkcija naj sestavi in vrne nov niz, ki ga dobi iz niza
sporocilo
tako, da vse samoglasnike prestavi na konec niza.
>>> disemvowel('Banana je dobra!')
'Bnn j dbr!aaaeoa'
def disemvowel(sporocilo): '''desemvowlanje sporočila''' brez = '' # niz brez samoglasnika samoglasniki = '' # vsi samoglasniki iz niza for c in sporocilo: if c in 'aeiouAEIOU': # gre za samoglasnik samoglasniki += c else: #"običajni" znak brez += c return brez + samoglasniki #zlepimo v pravem redu
Včasih pa želimo sporočilo dešifrirati, saj nas zanima njegova vsebina.
Ta naloga je vse prej kot enostavna, saj ne vemo kam točno je treba vriniti
izgnane samoglasnike. Sporočilo 'Bnn j dbr!aaaeoa'
bi lahko dešifrirali
tudi kot 'Banna ja debora!'
, kot 'Bnana aje dobar!'
ipd.
Bob Rock je na mesta v besedilu, kjer predvideva, da bi morali stati
samoglasniki, vstavil znake '*'
(zvezdica). V sporočilu zvezdica nikoli
ne bo imela drugega pomena. Prav tako bo število samoglasnikov enako številu
zvezdic in vsi samoglasniki bodo na koncu niza.
Napišite funkcijo razveljaviDisemvowel(niz)
, ki bo zvezdice v nizu
nadomestila s samoglasniki, ki se v nizu niz
nahajajo na koncu. Zgled:
>>> razveljaviDisemvowel('B*n*n* j* d*br*!aaaeoa')
'Banana je dobra!'
def razveljaviDisemvowel(niz): '''zvezdice v disemvowlanem nizu nadosmesti s samoglasniki s konca niza''' stZvezdic = niz.count('*') #da bomo vedeli, kje se začno samoglasniki if stZvezdic == 0: # ni kaj delati return niz samoglasniki = niz[-stZvezdic:] # odrežemo ustrezen del niza sporocilo = '' stevec = 0 # kje v nizu samogalsnikov smo for c in niz[:-stZvezdic]: # pregledamo le del niza brez končnih samoglasnikov if c == '*': # zvezdico nadomestimo z ustreznim samoglasnikom sporocilo += samoglasniki[stevec] stevec += 1 # premaknemo se naprej po samoglasnikih else: sporocilo += c return sporocilo
Učenci so se v šoli v naravi med prostim časom zabavali z različnimi besednimi igrami.
Ena izmed njih je bila ugibanje pomena čudnih besed. Pravilo je bilo, da so si zamišljali besede,
ki vsebujejo črkovno zvezo 'pa' in jo nadomestili z zvezo 'cveti'.
Tako so nastajale smešne besede kot na primer: cvetiprika, cveticvetigaj, nacvetidalec itd...
Sestavi funkcijo cvetoceBesede(niz)
, ki bo vrnila pravi pomen teh besed.
Pri tem ne smeš uporabiti funkcije replace!
Na primer:
>>>cvetoceBesede('cveticvetigaj')
papagaj
def cvetoceBesede(niz): '''izloči 'cveti' in nadomesti s 'pa' ''' pravaBeseda = '' i = 0 while i < len(niz) - 4: if niz[i:i+5] == 'cveti': # jemljemo po 5 znakov pravaBeseda += 'pa' # prvi dve zaporedni črki iz niza 'cveti' zamenja z 'pa', ostale tri pa izbriše i += 5 else: pravaBeseda += niz[i] i += 1 # prepišemo še mnorebitni preostanek while i < len(niz): pravaBeseda += niz[i] i += 1 return pravaBeseda def cvetoceBesedeV1(niz): '''izloči 'cveti' in nadomesti s 'pa' uporaba ukaza del ''' pravaBeseda='' if 'cveti' in niz: #ugotovi, če je v besedi besedna zveza "cveti" sezCvet=list(niz)#niz spremeni v seznam i=0 while i<len(sezCvet)-4: # prvi dve zaporedni črki iz niza 'cveti' zamenja z 'pa', ostale tri pa izbriše, nato pregleda še ostanek seznama if sezCvet[i:i+5]==['c', 'v', 'e', 't', 'i']: sezCvet[i]='p' sezCvet[i+1]='a' del sezCvet[i+2:i+5] i+=1 pravaBeseda=''.join(sezCvet) #seznam zopet spremeni v niz in ga vrne else: return niz return pravaBeseda def cvetoceBesedev2(niz): '''izloči 'cveti' in nadomesti s 'pa' uporabimo replace ''' pravaBeseda = niz.replace('cveti', 'pa') return pravaBeseda def cvetoceBesedev3(niz): '''izloči 'cveti' in nadomesti s 'pa' uporabimo split in join ''' pravaBeseda = 'pa'.join(niz.split('cveti')) return pravaBeseda
V vasi Muhačevo so bili navdušeni pevci in so radi prepevali znano ljudsko: "Priletela muha na zid."
Besedilo pesmi je povsem enostavno, saj se v bistvu ves čas ponavlja isto besedilo.
Posebnost pesmi je v tem, da se najprej poje tako, da se vsi samoglasniki spremenijo v a, nato v e in tako naprej,
dokler ne pridejo na vrsto vsi samoglasniki (a,e,i,o,u).
Sestavi funkcijo muha(niz)
, ki bo vpisano besedo ali besedno zvezo spremenila v seznam besed,
v katerih bodo najprej vsi samoglasniki a, nato e in še i, o in u.
Beseda je napisana z malimi tiskanimi črkami.
Na primer:
>>> muha('trobentica')
['trabantaca', 'trebentece', 'tribintici', 'trobontoco', 'trubuntucu'].
def muha(niz): '''vrne seznam besed, v katerih so spremenjeni vsi samoglasniki najprej v a, nato v e in tako naprej''' vsiSamoglasniki = 'aeiou' seznamBesed = [] for samoglasnik in vsiSamoglasniki: # uporabimo vse samoglasnike novaBeseda = '' for znak in niz: # pregledamo vse znake v nizu if znak in vsiSamoglasniki: # če gre za poljuben samoglasnik novaBeseda += samoglasnik # dodamo trenutno 'aktivnega' else: novaBeseda += znak # sicer ga le prepišemo seznamBesed.append(novaBeseda) # beseda z ustreznim samoglasnikom return seznamBesed
Učiteljica je dala učencem nalogo naj napišejo tri besede tako,
da se bo vsaka črka v vseh treh besedah pojavila natanko enkrat.
Vsako novo pojavitev iste črke bo štela za napako. Torej, če se bo črka a pojavila
trikrat, bosta to dve napaki.
Sestavi funkcijo besede(niz)
, ki bo preštela napake in vrnila, koliko napak je učenec naredil.
Pri tem so besede ločene z vejicami, ki niso del besed, vsi ostali zanki pa so!
Na primer:
>>>besede('miza,miha,zima')
7
>>>besede('mimi,ali,gremo')
4
def besede(niz): '''funkcija prešteje, kolikokrat se posamezne črke pojavijo več kot enkrat''' koliko = 0 črke = '' # katere črke so se že pojavile for znak in niz: if znak != ',': # vejice ignoriramo if znak in črke: # znak se je pojavil že prej koliko += 1 else: črke += znak # nov znak return koliko
Lojzku je dolgčas, zato se igra z velikimi praznimi škatlami, ki se
nahajajo v skladišču, v katerem dela. Dimenzije škatel so shranjene v
seznamu trojic. Na primer, trojica (50, 100, 100)
predstavlja
škatlo, ki je visoka 50 cm ter široka in dolga 100 cm.
S trojicami delamo tako kot s seznami, le spremijati ne moremo elementov.
Torej tro[0]
nam da prvi element iz trojice. Seveda pa lahko trojko tudi
"razpakiramo"
vis, sir, dol = skatla
če je skatla
neka trojka.
Sestavite funkcijo stolp(skatle)
, ki vrne višino najvišjega
stolpa, ki ga lahko sestavimo iz škatel, ne da bi jih obračali.
Pri tem ni treba paziti na stabilnost stolpa.
Na primer
>>>stolp([(50, 100, 100), (60, 30, 50), (40, 40, 40)])
150
def stolp(skatle): '''Višina stolpa iz škatel, če škatle zlagamo po višini (prvi dimenziji)''' skupnaVišina = 0 for skatla in skatle: # pregledamo vse škatle visina, sirina, dolzina = skatla skupnaVišina += visina return skupnaVišina ##Dodatno znanje nam da krajši zapis rešitve: ##def stolp(skatle): ## return sum(v for v, _, _ in skatle)
Sestavite funkcijo najvisjiStolp(skatle)
, ki vrne višino najvišjega
stolpa, ki ga lahko sestavimo iz škatel, če jih lahko obračamo.
Pri tem še vedno ni treba paziti na stabilnost stolpa.
Na primer, najvišji tak stolp iz škatel z dimenzijami (50, 100, 100),
(60, 50, 50) in (40, 40, 40) bi imel višino 200 cm, saj bi prvo škatlo
prevrnili na bok.
def najvisjiStolp(skatle): '''Kako visok je lahko stolp, če lahko škatle obračamo''' višina = 0 for skatla in skatle: višina += max(skatla) # pobrali smo največjo dimenzijo return višina ##Dodatno znanje nam da krajši zapis rešitve: ##def najvisjiStolp(skatle): ## return sum(max(v, s, d) for v, s, d in skatle)
Sestavite funkcijo greNotri(skatla1, skatla2)
, ki vrne True
, če
škatlo skatla1
lahko obrnemo tako, da gre v škatlo skatla2
, torej
da so dimenzije prve škatle strogo manjše od dimenzij druge škatle.
def poVrsti(trojka): ''' uredimo trojko (a, b, c) po velikosti (t1, t2, t3) so torej premešani a, b, c da velja t1 <= t2 <= t3 ''' a, b, c = trojka mal = min(a, b, c) vel = max(a, b, c) sre = a + b + c - mal - vel return (mal, sre, vel) def greNotri(skatla1, skatla2): '''Ali lahko skatlo1 damo v skatlo2''' nova1 = poVrsti(skatla1) nova2 = poVrsti(skatla2) return nova1[0] < nova2[0] and \ nova1[1] < nova2[1] and \ nova1[2] < nova2[2]
Sestavite funkcijo prestej(niz)
, ki prešteje, koliko zašiljenih
oklepajev tj. '<'
in '>'
je v nizu niz
. Primer:
>>> prestej('<abc>>')
3
>>> prestej('a>> x<Y>x <<b')
6
>>> prestej('Koliko oklepajev > in < je v tem nizu?')
2
Pri tem ne smeš uporabiti vgrajene metode count
def prestej(niz): '''Koliko je v nizu zašiljenih oklepajev''' koliko = 0 iskaniZnaki = "><" for znak in niz: if znak in iskaniZnaki: koliko += 1 return koliko
Niz imenujemo ukleščen, če se začne z predklepajem '<'
, konča
z zaklepajem '>'
, vmes pa ni nobenega znaka za zašiljene oklepaje.
Na primer, niz '<Zunaj sije sonce.>'
je ukleščen niz.
Sestavite funkcijo uklescen(niz)
, ki preveri, ali je niz niz
ukleščen.
Primer:
>>> uklescen('<Zunaj sije sonce.>')
True
>>> uklescen('< <3 >')
False
>>> uklescen('Zunaj sije sonce.')
False
def uklescen(niz): '''Ali je niz ukleščen''' if len(niz) < 2: # niz je prekratek! return False return niz[0] == '<' and niz[-1] == '>' and prestej(niz) == 2
Sestavite funkcijo sklop(niz1, niz2)
, ki prejme dva ukleščena niza
in vrne ukleščeni niz, ki predstavlja njun sklop. (Kaj je to sklop, je
razvidno iz spodnjega primera.) Primer:
>>> sklop('<123>', '<456>')
'<123456>'
>>> sklop('<muca>', '<copatarica>')
'<mucacopatarica>'
def sklop(niz1, niz2): '''Sklopimo dva ukleščena niza''' return niz1[:-1] + niz2[1:]
Sestavite funkcijo razlomi(niz, s)
, ki kot argumenta prejme
ukleščeni niz niz
in seznam nenegativnih celih števil s
ter vrne
seznam ukleščenih nizov, ki imajo dolžine, naštete v seznamu s
,
in skupaj tvorijo niz niz
. Primer:
>>> razlomi('<Zunaj sije sonce.>', [2, 7, 8])
['<Zu>', '<naj sij>', '<e sonce.>']
>>> razlomi('<muca copatarica>', [4, 0, 11])
['<muca>', '<>', '< copatarica>']
Predpostavite lahko, da bo vsota števil v seznamu s
enaka dolžini
ukleščenega niza niz
(če ne štejemo zašiljenih oklepajev).
def razlomi(niz, s): '''Razlomi ukleščen niz na manjše koščke in vrne seznam koščkov''' rez = [] k = 1 # kje začnemo ukleščeni niz for dolzina in s: rez.append('<' + niz[k:k+dolzina] + '>') k += dolzina return rez
Sestavite funkcijo palindrom(niz)
, ki vrne True
kadar je niz
palindrom, in False
sicer.
def palindrom(niz): '''Ali je niz palindrom''' return niz == niz[::-1]
Sestavite funkcijo palindromHitro(niz)
, ki vrne True
kadar je niz
palindrom, in False
sicer.
Če niz ni palindrom, naj to ugotovi kar se da hitro (npr. Matija
očitno ni palibndrom,
saj M
ni enak a
def palindromHitro(niz): '''Ali je niz palindrom''' for ind in range(1, len(niz) // 2 + 1): if niz[ind - 1] != niz[-ind]: # neujemajoča se znaka return False #vsi pari se ujemajo return True
Pravimo, da je beseda skoraj palindrom, če ji je treba zbrisati natanko eno črko, da bi postala palindrom. Primer je beseda 'kolo', ki ji moramo zbrisati črko 'k', pa postane palindrom 'olo'.
Sestavite funkcijo skorajPalindrom(niz)
, ki preveri, ali je niz
skoraj palindrom. Vse znake (tudi presledke) v besedi obravnavamo enako.
def skorajPalindrom(niz): '''ALi je niz skoraj palindrom''' # za vsak i poskusimo izpustiti črko na i-tem mestu for i in range(len(niz)): # če smo dobili palindrom, končamo if palindrom(niz[:i] + niz[i + 1:]): return True # če je zanka prišla do konca, palindroma nismo našli return False
Sestavite funkcijo vsebuje(niz1, niz2)
, ki za parametra dobi dva niza
ter vrne True
, če in samo če je mogoče prvi niz dobiti tako, da v
drugi niz na poljubnih mestih vstavljamo dodatne znake. (povedano
drugače, če prvi niz vsebuje vse znake iz drugega niza v ustreznem
vrstnem redu).
Iz besede 'ROLA' lahko na primer z vrivanjem znakov dobimo besedo 'pRikOLicA'. Med velikimi in malimi tiskanimi črkami strogo ločujemo.
def vsebuje(niz1, niz2): '''Ali je niz2 vsebovan v nizu1''' # v spremenljivki indeksNiz2 hranimo indeks znaka v malem nizu, ki ga iščemo indeksNiz2 = 0 for znakNiz1 in niz1: # če smo našli znak na indeksu indeksNiz2, iščemo naslednjega if niz2[indeksNiz2] == znakNiz1: indeksNiz2 += 1 # če smo našli vse znake v malem nizu, končamo if indeksNiz2 == len(niz2): return True # če se zanka konča, vseh znakov nismo našli return False
Sestavite funkcijo besede(niz)
, ki sestavi in vrne seznam parov
indeksov (začetek, konec), ki določajo, kje v danem nizu se nahajajo
posamezne besede. Beseda je maksimalno zaporedje znakov, ki ne vsebuje
presledka.
>>> besede('Danes je lep dan, saj ne dežuje.')
[(0, 4), (6, 7), (9, 11), (13, 16), (18, 20), (22, 23), (25, 31)]
>>> besede(' abc abc abc ')
[(1, 3), (6, 8), (11, 13)]
def besede(stavek): '''Seznam položajev besed''' indeksi = [] # ali smo našli besedo, ali smo pri presledkih smo_v_besedi = False # zacetek trenutne besede zacetek = 0 for i in range(len(stavek)): z = stavek[i] # ta in prejšnji stavek lahko nadomestimo z enim # for i, z in enumerate(stavek): # če smo v besedi in najdemo presledek, dodamo njene indekse v seznam if smo_v_besedi and z == ' ': smo_v_besedi = False indeksi.append((zacetek, i - 1)) # če nismo v besedi in najdemo znak, začnemo z besedo elif not smo_v_besedi and z != ' ': smo_v_besedi = True zacetek = i # če smo na koncu zanke še vedno v besedi, ta beseda sega do konca if smo_v_besedi: indeksi.append((zacetek, len(stavek) - 1)) return indeksi
Vsote peterk
Podan je seznam nenegativnih števil in naloga je poiskati največjo vsoto
petih zaporednih števil v tem seznamu. Napiši funkcijo vsota_peterk(sez)
,
ki prejme seznam nenegativnih števil sez
in vrne največjo vsoto.
Če je v seznamu manj kot 5 štervil, vrni -1.
Primer (največja vsota je pri 3, 8, 9, 0, 4):
>>> vsota_peterk([9, 1, 2, 3, 8, 9, 0, 4, 3, 7])
24
def vsota_peterk(sez): '''Vrne maksimalno vsoto pet zaporednih elementiov seznama''' if len(sez) < 5: return -1 najvecja = 0 # doslej največja vsota for zacetek in range(len(sez) - 4): # preverjamo samo do 5. elementa na koncu vsota = sum(sez[zacetek : zacetek + 5]) # sestevamo po 5 elementov naenkrat if vsota > najvecja: # ce je trenutna vsota vecja od najvecje najvecja = vsota # smo nasli novo najvecjo vsoto return najvecja
Sestavi funkcijo, ki za dani seznam in naravno število k
izračuna in vrne
seznam vsot vseh strnjenih podseznamov dolžine k
.
>>> vsote([1, 2, 3, 4], 2)
[3, 5, 7]
>>> vsote([2, 6, 3, 7, 5, 2, 3], 3)
[11, 16, 15, 14, 10]
>>> vsote([3, 5, 1], 1)
[3, 5, 1]
>>> vsote([3, 5, 1], 3)
[9]
>>> vsote([3, 5, 1], 4)
[]
def vsote(sez, k): '''vsote vseh strnjenih podseznamov dolžine k''' if k > len(sez): #nimamo nobenega takega podseznama return [] vsota = 0 #najprej seštejemo prvih k for i in range(k): vsota += sez[i] sezVsot = [vsota] #sedaj pa gremo do konca seznama in prištejemo konec in odštejemo začetek for i in range(k, len(sez)): vsota = vsota - sez[i-k] + sez[i] sezVsot.append(vsota) return sezVsot
Razmisli, kako bi rešil nalogo, kjer moramo poiskati največjo vsoto
strnjenega podzaporedja, če je seznam
zelo velik (> 100 000) in iščemo največjo vsoto daljših (> 10 000)
zaporedij števil. Napiši funkcijo
max_vsota_nterk(s, n)
, kjer je s
seznam števil in n
število zaporednih števil.
Če bi morali poiskati vsoto desettisočerk, bi moral na vsakem koraku sešteti 10 000 števil, to bi storili skoraj milijonkrat. Vsega skupaj bi seštel deset milijard števil, za kar bi potrebovali kar nekaj časa.
Pri preverjanju na sistemu Tomo - če odgovora ne dobiš v recimo 20 sekundah
- s CTRL-C
prekini program, saj tvoja rešitev očitno ni dovolj hitra!
def max_vsota_nterk(s, n): '''Računanje naj n-terke v velikih seznamih''' najvecja = vsota = sum(s[:n]) # začetni kandidat je vsota prvih n for i in range(n, len(s)): # sestevamo ze sproti vsota += s[i] - s[i-n] # vsakic ko povecamo indeks za 1, se if vsota > najvecja: # prvi element odsteje, naslednji pa doda najvecja = vsota return najvecja
Sestavite funkcijo zacetek(a, b)
, ki bo za niza a
in b
preštela,
v koliko začetnih znakih se ujemata.
Niza nimata nujno enakega začetka, lahko se delno ujemata na začetku, lahko se en niz v celoti pojavi na začetku drugega, ali pa sta niza celo enaka. Ni potrebno obravnavati vsakega od teh primerov posebej, samo pazite, da bo funkcija delala pravilno za vse primere.
>>> zacetek('matematika', 'fizika')
0
>>> zacetek('matematika', 'matija')
3
>>> zacetek('oder', 'oderuh')
4
>>> zacetek('izpit', 'izpit')
5
Pri rešitvi obvezno uporabite zanko while
.
def zacetek(a, b): ''' v koliko začetnih znakih se ujemata niza a in b''' i = 0 dolžinaKrajšega = min(len(a), len(b)) while i < dolžinaKrajšega and a[i] == b[i]: i += 1 return i
Sestavite funkcijo zacetekFor(a, b)
, ki bo za niza a
in b
preštela,
v koliko začetnih znakih se ujemata.
Pri rešitvi ne smete uporabiti zanke while
.
def zacetekFor(a, b): ''' v koliko začetnih znakih se ujemata niza a in b''' najkrajsi = min(len(a),len(b)) for i in range(najkrajsi): # ustaviti se moramo, ko krajšega niza zmanjka if a[i] != b[i]: return i # i-ti znak je prvi neujemajoči, ker štejemo od 0 dalje ... return najkrajsi # ujemala sta se v vseh
Napiši funkcijo st_ujemanj(b1, b2)
, ki prejme dve besedi in vrne število
znakov, v katerih se besedi ujemata.
Primeri:
>>> st_ujemanj("ROKA", "ROKAV")
4
>>> st_ujemanj("CELINKE", "POLOVINKE")
1
def st_ujemanj(b1, b2): '''Koliko istoležnih znakov je enakih''' ujemanja = 0 for i in range(min(len(b1), len(b2))): # zanka se izvede tolikokrat koliko je dolga najkrajsa beseda b1 oz. b2 if b1[i] == b2[i]: # ce sta znaka v obeh besedah enaka, se ujemanje poveca za 1. ujemanja += 1 return ujemanja
Napiši funkcijo ujeme(b1, b2)
, ki kot vhod prejme dve besedi b1
in b2
, ter vrne
novo besedo, ki vsebuje tiste znake, v katerih se besedi ujemata (imata na istem mestu isti znak),
znaki na ostalih mestih pa so zamenjane s pikami. Če besedi nista enako dolgi,
naj bo nova beseda toliko dolga, kolikor je dolga krajša izmed podanih
besed.
Primeri:
>>> ujeme("ROKA", "REKE")
'R.K.'
>>> ujeme("ROKA", "ROKAV")
'ROKA'
def ujeme(b1, b2): '''Vrne niz, ki označuje, kako se ujkemata niza''' rezultat = "" for i in range(min(len(b1), len(b2))): if b1[i] == b2[i]: # ce sta znaka enaka rezultat += b1[i] # potem v rezultat dodamo ta znak else: rezultat += "." # sicer dodamo piko. return rezultat
Žaba (Salientia) skače po ravnini. Na začetku in po vsakem skoku zabeležimo
projekcijo točke (tj. položaja žabe) na abscisno in ordinatno os, s
čemer dobimo seznama px
in py
. Sestavili bomo sklop funkcij, s katerimi bomo
analizirali žabino gibanje.
Sestavite funkcijo vPravokotniku(tocka, pravokotnik)
, ki za dano
točko tocka
vrne True
, če je točka znotraj ali na robu pravokotnika
pravokotnik
. Točka v ravnini je podana s seznamom
def vPravokotniku(tocka, pravokotnik): [x, y] = tocka [x1, y1, x2, y2] = pravokotnik (x1, x2) = (min(x1, x2), max(x1, x2)) (y1, y2) = (min(y1, y2), max(y1, y2)) return x1 <= x and x <= x2 and y1 <= y and y <= y2
Sestavite funkcijo pot(px, py)
,
ki iz danih seznamov px
in py
rekonstruira pot žabe,
tj. vrne seznam točk, v katerih je bila žaba. Točko podano kot seznam dolžine 2.
>>> pot([0, 0, 1, 2], [0, 1, 2, 1]))
[[0, 0], [0, 1], [1, 2], [2, 1]]
Predpostavite lahko, da sta seznama px
in py
enakih dolžin.
def pot(px, py): '''Določi točke na žabini poti''' kje = 0 seznam = [] while kje < len(px): seznam.append([px[kje], py[kje]]) kje += 1 return seznam ##dodatno znanje nam da enovrstični zapis: ## ##def pot(px, py): ## return [[x, y] for x, y in zip(px, py)]
Sestavite funkcijo najdaljsiSkok(tocke)
, ki iz seznama tocke
, v
katerih so zapisane točke, po katerih je skakala žaba, izračuna dolžino
najdaljšega skoka.
Če žaba ni naredila nobenega skoka, naj funkcija vrne None
.
def d(a, b): '''Razdalja med točkama a in b''' return ((a[0] - b[0])**2 + (a[1] - b[1])**2)**0.5 def najdaljsiSkok(tocke): '''Kako dolg je najdaljši skok''' if len(tocke) <= 1: return None najSkok = -1 doskok = 1 # indeks, kjer je žaba doskočila while doskok < len(tocke): skok = d(tocke[doskok], tocke[doskok - 1]) if skok > najSkok: # je skok daljši? najSkok = skok doskok += 1 return najSkok ##dodatno znanje nam da krajši zapis: ##def najdaljsiSkok(tocke): ## if len(tocke) <= 1: ## return None ## else: ## return max([d(tocke[i], tocke[i - 1]) for i in range(1, len(tocke))])
Žaba skače po ravnini in po nekaj skokih skoči v pravokotno blatno
mlako. Sestavite funkcijo vMlaki(tocke, mlaka)
, ki naj vrne prvi
podseznam skokov, ki v celoti potekajo po mlaki. Pri tem so skoki
podani s seznamom vmesnih točk tocke
, pravokotna mlaka pa s četverico
mlaka
, ki je oblike [x1, y1, x2, y2]
kot v prvi podnalogi.
Če takega podseznama ni, naj funkcija vrne None.
def vMlaki(tocke, mlaka): '''Vrne prvi seznam skokov, ki potekajo po mlaki''' podSeznam = None katera = 0 while katera < len(tocke): tocka = tocke[katera] if vPravokotniku(tocka, mlaka): # če smo v mlaki if podSeznam == None: # še nimamo podseznama podSeznam = [tocka] else: podSeznam.append(tocka) elif podSeznam == None: # če nismo v mlaki in # sploh še nismo skočili v mlako katera += 1 continue # skačemo naprej else: break # konec veselja, bili smo v mlaki in smo skočili ven katera += 1 return podSeznam
Igro življenja si je izmislil britanski matematik John H. Conway,
gre
pa takole: Imamo matriko, katere elementi sta logični vrednosti True
in False
. Vrednost True
pomeni, da je celica živa, vrednost False
pa pomeni, da je celica mrtva. Celice (razen robnih) imajo po 8 sosedov:
dva horizontalna, dve vertikalna in štiri diagonalne. Čas teče v
diskretnih korakih. S trenutnim stanjem sveta je tudi stanje sveta
v naslednjem koraku natanko določeno in sicer po naslednjih pravilih:
Primeri matrik, ki predstavljajo stanje sveta:
svet_1 = [
[False, False, False, False, False, False],
[False, False, False, True, False, False],
[False, True, False, False, True, False],
[False, True, False, False, True, False],
[False, False, True, False, False, False],
[False, False, False, False, False, False]
]
svet_2 = [
[False, False, False, False],
[False, True, True, False],
[False, True, True, False],
[False, False, False, False]
]
Tukaj si lahko ogledate simulacijo
Napišite funkcijo zivi(svet, i, j)
, ki v svetu svet
prešteje in
vrne število živih sosedov celice v svet_1
matrika, kot je definirana zgoraj):
>>> zivi(svet_1, 2, 0)
2
Opomba: Kot je za Python običajno, se stolpci in vrstice začnejo številčiti pri 0.
def zivi(svet, i, j): '''Koliko živih sosedov ima celica (i,j) ''' n, m = len(svet), len(svet[0]) # dimenzije sveta stej = 0 for vrst in range(i-1, i+2): for stol in range(j-1, j+2): if (vrst == i) and (stol == j): # sama sebi ni sosed continue if (vrst < 0) or (vrst > n-1) or (stol < 0) or (stol > m-1): # smo izven sveta continue if svet[vrst][stol] : # živ sosed! stej += 1 return stej
Napišite funkcijo igra(svet)
, ki sestavi in vrne matriko, ki
predstavlja novo stanje sveta. Štiri pravila, ki določajo novo stanje
sveta, so opisana zgoraj.
Zgled (matrika svet_1
naj bo enaka kot zgoraj):
>>> igra(svet_1)
[[False, False, False, False, False, False],
[False, False, False, False, False, False],
[False, False, True, True, True, False],
[False, True, True, True, False, False],
[False, False, False, False, False, False],
[False, False, False, False, False, False]]
def igra(svet): '''vrne nov svet po enem koraku''' n, m = len(svet), len(svet[0]) novSvet = [] for i in range(n): # po vrsticah novaVr = [] for j in range(m): # po stolpcih novaVr.append(zivi(svet, i, j) == 3 or # celica ima tri žive sosede (zivi(svet, i, j) == 2 and svet[i][j])) # ali pa 2 in je ona živa novSvet.append(novaVr) return novSvet ## Z nekaj več znanja lahko napišemo le ## n, m = len(svet), len(svet[0]) ## return [[zivi(svet, i, j) == 3 or \ ## (zivi(svet, i, j) == 2 and svet[i][j]) for j in range(m)] for i in range(n)]
Napišite funkcijo populacija(svet, n)
, ki naredi n
korakov igre
življenje in na vsakem koraku prešteje število živih celic. Ta
števila naj vrne v obliki seznama, ki ima svet_1
naj bo enaka kot zgoraj):
>>> populacija(svet_1, 3)
[6, 6, 6, 6]
Funkcijo bomo testirali še na naslednjih svetovih (poleg tistih dveh, ki sta podana zgoraj):
svet_3 = [
[False, False, False, False, False, False],
[False, True, True, False, False, False],
[False, True, True, False, False, False],
[False, False, False, True, True, False],
[False, False, False, True, True, False],
[False, False, False, False, False, False]
]
svet_4 = [
[True, True, True],
[True, True, True],
[True, True, True]
]
Nasvet: Najprej napišite pomožno funkcijo, ki prešteje število živih celic v matriki.
def kolikoŽivih(svet): '''Koliko je v svetu živih celic''' n, m = len(svet), len(svet[0]) koliko = 0 for i in range(n): # po vrsticah novaVr = [] for j in range(m): # po stolpcih if svet[i][j] : # živa celica! koliko += 1 return koliko def populacija(svet, n): '''Kako se v n korakih spreminja populacija živih celic''' ret = [kolikoŽivih(svet)] # stanje na začetku for i in range(n): # koliko korakov svet = igra(svet) # nov svet ret.append(kolikoŽivih(svet)) # dodamo število živih return ret ## Z nekaj več znanja: ## ## def kolikoŽivih(svet): ## return sum(sum(1 if x else 0 for x in vr) for vr in svet) ## ## def populacija(svet, n): ## ret = [pop(svet)] ## for i in range(n): ## svet = igra(svet) ## ret.append(kolikoŽivih(svet)) ## return ret
Pri tej nalogi bomo analizirali nize, ki predstavljajo pravilno slovensko
oblikovane besede in stavke. Pri vseh podnaloge lahko predpostavite, da
so vhodni nizi s
dobro oblikovani, tj. ne vsebujejo dveh zaporednih
presledkov oz. nepotrebnih presledkov ter prelomov vrstice na začetku ali
na koncu.
Sestavite funkcijo stevilo_besed(s)
, ki v podanem nizu prešteje
število besed, pri čemer lahko predpostavite, da presledki stojijo
natanko pred vsako (razen prvo) besedo v nizu. Primer:
>>> stevilo_besed('Višje, hitreje, močneje!')
3
def stevilo_besed(s): '''Koliko besed je v nizu s''' if s == '': return 0 return s.count(' ') + 1 # +1 zaradi prve besede
Sestavite funkcijo samoglasniki(s)
, ki v podanem nizu s
prešteje
število samoglasnikov. Zgled:
>>> samoglasniki('pomaranča')
4
def samoglasniki(s): '''Koliko je v nizu s samoglasnikov''' vsiSamoglasniki = 'aeiouAEIOU' stevec = 0 for c in s: if c in vsiSamoglasniki: stevec += 1 return stevec
V Pythonu vrstice večvrstičnega niza ločujemo z znakom '\n'
.
Sestavite funkcijo vrstice(s)
, ki sprejme večvrstični niz s
in
vrne seznam, ki vsebuje vse vrstice tega niza (v istem vrstnem redu).
Zgled:
>>> vrstice("Danes\n je lep\ndan.\n")
['Danes', ' je lep', 'dan.', '']
Opomba: Python obravnava niz '\n'
kot en sam znak.
def vrstice(s): '''Vrne seznam vrstic v nizu s''' return s.split('\n')
Haiku (japonsko 俳句) je japonska pesniška oblika iz treh verzov (vrstic), ki obsega sedemnajst zlogov. Prvi in tretji verz imata po pet zlogov, drugi sedem.
Na kulturnem natečaju TomoHaiku udeleženci oddajajo svoje izdelke na
strežnik Tomo. Napišite kontrolno funkcijo haiku(s)
, ki sprejme
niz s
, ter vrne True
, če niz ustreza pesniški obliki haiku, sicer
pa vrne False
.
Predpostavite lahko, da število samoglasnikov v neki besedi ustreza
številu njenih zlogov, ter da niz s
ne vsebuje nepotrebnih začetnih oz.
končnih praznih vrstic. Vrstice so ločene z znakom za prelom vrstice '\n'
.
Primer:
>>> haiku('Skrit v svojem svetu,\ntemna otožnost neba,\ntvoj topli objem.')
True
>>> haiku('Riba,\nraca, rak,\nvinjak je grenak!')
False
def haiku(s): '''Preveri, ali je v nizu s zapisan haiku''' if s.count('\n') != 2: # premalo vrstic return False i = s.find('\n') # konec prve vrstice j = s.find('\n', i + 1) # konec druge # prva in tretja morate imeti 5, srednja pa 7 samoglasnikov return samoglasniki(s[:i]) == samoglasniki(s[j:]) == 5 and samoglasniki(s[i:j]) == 7
Sestavite funkcijo podcrtaj(s)
, ki za parameter dobi niz s
, v
katerem so podnizi, ki bi morali biti izpisani podčrtano, označeni s
podčrtajem na začetku in na koncu. Če je v nizu liho mnogo podčrtajev,
si mislite, da je še eden na koncu. Funkcija naj vrne dvovrstični niz,
kjer je v prvi vrstici originalni niz s
toda brez podčrtajev, sledi
znak za prelom vrstice, naslednjo vrstico pa sestavlja niz, sestavljen
iz presledkov in minusov, pri čemer minusi ležijo pod tistimi deli
besedila, ki morajo biti podčrtani. Primer:
>>> podcrtaj("Jaz _sem_ pa cajzelc!")
'Jaz sem pa cajzelc!\n --- '
Predpostavite, da v nizu s
ni nobenega znaka '\n'
.
def podcrtaj(s): '''Vrne niz iz dveh vrstic, kjer so ustrezni znaki podčrtani''' prvaVrsta = '' drugaVrsta = '' podcrtujem = False # ali so trenutni znaki podčrtani for znak in s: if znak == '_': # preklopimo način podčrtovanja podcrtujem = not podcrtujem else: prvaVrsta += znak # v prvi vrsti so vsi znaki razen podčrtajev if podcrtujem: # v drugi pa bodisi presledki, bodisi podčrtaji drugaVrsta += '-' else: drugaVrsta += ' ' return prvaVrsta + '\n' + drugaVrsta
Sestavite funkcijo stevilo_znakov(s)
, ki v podanem nizu s
prešteje
število znakov, pri čemer se presledki ne upoštevajo. Zgled:
>>> stevilo_znakov('B u!')
3
def stevilo_znakov(s): '''Število znakov brez presledkov''' return len(s) - s.count(' ')
Sonet je priljubljena pesniška oblika. Sestavljen je iz štirih kitic, pri čemur med vsakima dvema kiticama avtor izpusti eno prazno vrstico. Prvi dve kitici sta štirivrstični — kvartini, drugi dve pa sta trivrstični — tercini.
V slovenskem sonetu je standardni verz italijanski (laški) ali jambski enajsterec. To pomeni, da v vsaki vrstici nastopa natanko enajst zlogov.
Na kulturnem natečaju TomoSonet udeleženci oddajajo svoje izdelke na
strežnik Tomo. Napiši kontrolno funkcijo sonet(s)
, ki sprejme niz
s
, ter vrne True
, če niz ustreza slovenskemu sonetu, in False
sicer.
Zgled:
>>> sonet('Bolj slab\nsonet.\n\nZa umret!')
False
Namig: V slovenskem jeziku število samoglasnikov v neki besedi ustreza številu njenih zlogov. (Obstaja nekaj izjem, ki pa jih bomo zanemarili.)
def sonet(s): '''Ali je v s zapisan sonet''' v = vrstice(s) # seznam vrstic - s pomočjo funkcije od prej! if len(v) != 17: return False # Sonet mora imeti 14 + 3 (prazne) = 17 vrstic. for i in range(17): # indeksi vseh vrstic if i in [4, 9, 13]: if v[i] != '': return False # Med kiticami morajo biti prazne vrstice. else: if samoglasniki(v[i]) != 11: return False # Verz ni jambski enajsterec. return True
Klodovik /papiga/ in ne
Klodvik, frankofonski kralj/
bi rad zašifriral svoja besedila, da jih nepoklicane osebe
ne bodo mogle prebrati. To stori tako, da najprej v besedilu vse male
črke spremeni v velike in odstrani vse znaki, ki niso črke. (Klodvik
vsa pomembna besedila piše v angleščini. Uporabljali bomo angleško
abecedo.) Na primer iz besedila 'Attack at dawn!'
dobi besedilo
'ATTACKATDAWN'
. Nato ga zapiše cik-cak v treh vrsticah, kot prikazuje
primer:
A...C...D...
.T.A.K.T.A.N
..T...A...W.
Sestavite funkcijo cik_cak(s)
, ki vrne trojico nizov (torej tuple
) in sicer prvo,
drugo in tretjo vrstico v tem zapisu. Primer:
>>> cik_cak('Attack at dawn!')
('A...C...D...', '.T.A.K.T.A.N', '..T...A...W.')
def cik_cak(niz): '''Niz spremenimo v trtvrstični zapis CikCak''' perioda = [0, 1, 2, 1] # kako se izmenjujejo nizi, kamor # zapišemo znak: prva, druga, tretja, druga, prva, druga, tretja, druga ... niz = niz.upper() vrste = ['', '', ''] # vrstice bodo na začetku seznami, da jih lahko spreminjamo! stevec = 0 # kateri znak jemljemo for znak in niz: if not 'A' <= znak <= 'Z': # če ne gre za znak angleške abecede continue pos = perioda[stevec % 4] # kam bomo napisali znak vrste[pos] += znak vrste[(pos+1)%3] += '.' vrste[(pos+2)%3] += '.' stevec += 1 return tuple(vrste) # vrniti moramo trojico!
Zašifrirano besedilo dobi tako, da najprej prepiše vse znake iz prve
vrstice, nato vse znake iz druge vrstice in na koncu še vse znake iz
tretje vrstice. V zgornjem primeru bi tako dobil 'ACDTAKTANTAW'
.
Sestavite funkcijo cik_cak_sifra(s)
, ki dobi kot argument niz s
in vrne zašifrirano besedilo. Primer:
>>> cik_cak_sifra('Attack at dawn!')
'ACDTAKTANTAW'
def cik_cak_sifra(s): '''Zašifrirajmo besedilo''' prva, druga, tretja = cik_cak(s) # najprej zapišemo cik-cak sifra = '' for znak in prva + druga + tretja: # gremo preko vseh treh vrstic if znak != '.': # spustimo pike sifra += znak return sifra
Klodovik se zelo razjezi, ko dobi elektronsko pošto v takšni obliki:
Kar sva si obljubljala že leta, si želiva potrditi tudi pred prijatelji in celo
žlahto. Vabiva te na
poročno slovesnost, ki bo
10. maja 2016 ob 15. uri na gradu Otočec. Prijetno druženje bomo
nadaljevali v hotelu Mons. Tjaša in Pavle
Nepopisno mu gre na živce, da je med besedami po več presledkov. Še bolj pa ga nervira, ker so nekatere vrstice precej daljše od drugih. Ker je Klodvik vaš dober prijatelj, mu boste pomagali in napisali funkcije, s katerimi bo lahko olepšal besedila.
Najprej napišite funkcijo razrez(s)
, ki kot argument dobi niz s
in vrne
seznam besed v tem nizu. Besede so med seboj ločene z enim ali večimi
praznimi znaki: ' '
(presledek), '\t'
(tabulator) in '\n'
(skok
v novo vrstico). Pri tej nalogi ločilo obravnavamo kot del besede.
Primer:
>>> razrez(' Kakšen\t pastir, \n\ntakšna čreda. ')
['Kakšen', 'pastir,', 'takšna', 'čreda.']
def razrez(s): '''Niz s razreže na podnize, ki jih ločijo "beli" presledki''' seznam = [] beseda = '' # trenutna beseda, ki jo sestavljamo for znak in s: if znak in ' \n\t': # znak ni del besede if len(beseda) > 0: # če je ta znak zaključil besedo, jo dodamo v seznam seznam.append(beseda) beseda = '' # in nato bomo začeli sestavljati novo else: beseda += znak # smo "znotraj" besede if len(beseda) > 0: # ne pozabimo na morebitno besedo na koncu! seznam.append(beseda) return seznam
Sedaj, ko že imate funkcijo razrez(s)
, bo lažje napisati tisto funckijo, ki
jo Klodovik zares potrebuje. To je
funkcija olepsanoBesedilo(s, sir)
, ki kot argumenta dobi niz
s
in naravno število sir
. Funkcija vrne olepšano besedilo, kar
pomeni naslednje:
sir
znakov (pri čemer znaka
'\n'
na koncu vrstice ne štejemo).Predpostavite, da dolžina nobene besede ni več kot sir
in da je niz
s
neprazen. Primer:
>>> s2 = olepsanoBesedilo(' Jasno in svetlo \t\tna sveti \t\n\nvečer, dobre\t\t letine je dost, če pa je\t oblačno in temno, žita ne bo.', 20)
>>> print(s2)
Jasno in svetlo na
sveti večer, dobre
letine je dost, če
pa je oblačno in
temno, žita ne bo.
def olepsanoBesedilo(s, sir): '''olepša besedilo do največje širine sir''' besedilo = '' #končno besedilo besede = razrez(s) # razrežemo na posamezne besede vrstica = '' for b in besede: if len(vrstica) + len(b) > sir: # če je beseda, ki je na vrsti, predolga besedilo += vrstica[:-1] + '\n' # odrežemo presledek, ki smo ga dodali za stikanje vrstica = '' # začnemo novo vrstico vrstica += b + ' ' if len(vrstica) > 0: # ne pozabimo na zadnjo vrstico! besedilo += vrstica[:-1] + '\n' return besedilo[:-1] # na koncu je odvečni prehod v novo vrsto
Srednje šole po Sloveniji si prizadevajo, da bi njihovi dijaki jedli čim bolj zdravo malico. Ravnatelj ene od srednjih šol je vaš dobri prijatelj. Rad bi, da mu napišete program, s katerim bo lahko analiziral jedilnike, saj si želi, da bi bili njegovi dijaki zdravi in srečni.
primer_jedilnika = [
'svinjski zrezek v omaki', 'sirov kanelon', 'ocvrt oslič',
'svinjski zrezek v omaki', 'ocvrt oslič', 'sirov burek',
'sirov kanelon', 'ocvrt oslič', 'sirov kanelon', 'sirov kanelon'
Jedilnik opišemo s seznamom nizov, kot vidite na primeru.
Vsak zaporedni element seznama ustreza enemu od zaporednih dni.
Jedilnik se periodično ponavlja. Če je dolžina jedilnika brez_ponovitev(l)
,
ki sestavi nov seznam, tako da se bo vsak element pojavil samo enkrat.
Zgled:
>>> brez_ponovitev(primer_jedilnika)
['svinjski zrezek v omaki', 'sirov kanelon', 'ocvrt oslič', 'sirov burek']
Elementi naj se v novem seznamu pojavijo v takem vrstnem redu, kot
njihove prve ponovitve v originalnem seznamu l
.
def brez_ponovitev(jedilnik): '''sestavi jedilnik brez ponovitev''' novJedilnik = [] for jed in jedilnik: if jed not in novJedilnik: # če jed še ni v novem jedilniku novJedilnik.append(jed) return novJedilnik
Ravnatelj je sicer ugotovil, da se jedi ponavljajo. Če pa je od
dneva, ko je bila neka jed nazadnje na jedilniku, minilo dovolj časa,
ni s tem nič narobe. Napišite funkcijo kdaj_prej(l)
, ki dobi nek
jedilnik in vrne enako dolg seznam, kjer je za vsak dan ena številka
in sicer koliko dni je minilo od takrat, ko je bila jed nazadnje na
jedilniku. Upoštevajte, da je jedilnik periodičen, torej jedilnik
['burek', 'jogurt', 'burek'] je v 5 dneh ['burek', 'jogurt', 'burek', 'burek', 'jogurt']
v 10 pa ['burek', 'jogurt', 'burek', 'burek', 'jogurt', 'burek', 'burek',
'jogurt', 'burek', 'burek']
Primer:
>>> kdaj_prej(['burek', 'jogurt', 'burek'])
[1, 3, 2]
>>> kdaj_prej(primer_jedilnika)
[7, 2, 5, 3, 2, 10, 5, 3, 2, 1]
def kdaj_prej(jedilnik): '''Koliko dni je minilo pred enako jednjo''' ustrezniIndeksi = [] n = len(jedilnik) for dan in range(n): j = dan - 1 # dan prej jedTaDan = jedilnik[dan] while jedilnik[j%n] != jedTaDan: #kdaj je bila ta jed prej j -= 1 ustrezniIndeksi.append(dan - j) return ustrezniIndeksi
Ravnatelj je definiral pojma raznolikost in kakovost. (Opomba:
Ravnatelj je študiral matematiko in jo svoje čase tudi poučeval.)
Raznolikost je število različnih jedi na jedilniku. Kakovost pa
je povprečje kvadratov vrednosti elementov seznama, ki ga vrne funkcija
kdaj_prej(l)
. Sestavite funkcijo raznolikost_in_kakovost(l)
, ki
vrne par števil in sicer raznolikost in kakovost jedilnika l
. Primer:
>>> raznolikost_in_kakovost(['burek', 'burek', 'jogurt'])
(2, 4.666666666666667)
>>> raznolikost_in_kakovost(primer_jedilnika)
(4, 23.0)
def raznolikost_in_kakovost(jedilnik): '''Vrne raznolikost in kakovost jedilnika''' jedilnikBP = brez_ponovitev(jedilnik) # število različnih jedi bo raznolikost! kdajPrej = kdaj_prej(jedilnik) # koliko nazaj je bila posamezna jed vsotaKv = 0 for kolikoNazaj in kdajPrej: vsotaKv += kolikoNazaj**2 povp = vsotaKv / len(kdajPrej) return len(jedilnikBP), povp
Ravnatelj je v zbornici zbral različne predloge jedilnikov in jih
združil v en sam seznam. Sestavite funkcijo naj_jedilnik(ll)
, ki
izmed vseh teh jedilnikov v seznamu ll
izbere in vrne najboljšega.
Bolši je tisti jedilnik, ki je bolj raznolik. Med jedilniki z enako
raznolikostjo je boljši tisti, ki je kakovostnejši. Predpostavite, da
imate vsaj en jedilnik in da
v podatkih ne bo dveh enako dobrih jedilnikov. Primer:
>>> naj_jedilnik([['burek', 'jogurt'], ['pomaranča', 'pomaranča']])
['burek', 'jogurt']
>>> naj_jedilnik([['burek', 'jogurt'], primer_jedilnika])
['svinjski zrezek v omaki', 'sirov kanelon', 'ocvrt oslič',
'svinjski zrezek v omaki', 'ocvrt oslič', 'sirov burek',
'sirov kanelon', 'ocvrt oslič', 'sirov kanelon', 'sirov kanelon']
def naj_jedilnik(seznamJedilnikov): '''Iz seznama jedilnikov poiščemo najboljšega''' naj = seznamJedilnikov[0] # kandidat za najboljšega je prvi for jedilnik in seznamJedilnikov[1:]: # pregledamo še ostale if raznolikost_in_kakovost(jedilnik) > raznolikost_in_kakovost(naj): # pari se primerjajo "leksikografsko" naj = jedilnik return naj
FizzBuzz je priljubljena otroška igrica, ki se jo lahko igrajo vsi otroci, ki znajo deliti cela števila. Otroci se usedejo v krog in štejejo (začenši z 1), pri čemer številke glasno izgovarjajo. Če je število deljivo s 3, potem morajo (namesto številke) zaklicati ‘Fizz!’. Če je število deljivo s 5, morajo zaklicati ‘Buzz!’. Če pa je število deljivo s 3 in 5 hkrati, morajo zaklicati ‘Fizzbuzz!’.
Sestavite funkcijo fizzbuzz(n)
, ki kot argument dobi naravno število
n
in vrne seznam števil od 1 do
'Fizz'
,'Buzz'
,'FizzBuzz'
.Primer:
>>> fizzbuzz(16)
[1, 2, 'Fizz', 4, 'Buzz', 'Fizz', 7, 8, 'Fizz', 'Buzz', 11, 'Fizz', 13, 14, 'FizzBuzz', 16]
def fb(n): '''Kaj naj pove, če je na vrsti n''' if n % 15 == 0: # večkratnik 15 moramo preveriti prvega! return 'FizzBuzz' if n % 3 == 0: return 'Fizz' if n % 5 == 0: return 'Buzz' return n def fizzbuzz(n): '''Vrne seznam ustreznih besed za igro Fizz buzz, če števejo do n''' seznamBesed = [] for i in range(1, n+1): seznamBesed.append(fb(i)) return seznamBesed
Sestavite še funkcijo poisci_napake(l)
, ki kot argument prejme
seznam l
. Ta seznam je FizzBuzz zaporedje, ki lahko vsebuje napake.
Funkcija naj vrne seznam vseh indeksov seznama l
, kjer se pojavijo
napake. Elementi izhodnega seznama naj bodo urejeni naraščajoče. Zgled:
>>> poisci_napake([1, 2, 3, 'Fizz', 'Buzz', 7, 'Fizz', 8])
[2, 3, 5, 6]
def poisci_napake(l): '''Poiščemo indekse, kjer je v seznamu l, napaka za igro FizzBuzzz''' napake = [] pravilno = fizzbuzz(len(l)) for i in range(len(l)): if l[i] != pravilno[i]: napake.append(i) return napake
Sestavite funkcijo prva_vrstica(ime_datoteke)
, ki vrne prvo vrstico
datoteke z danim imenom.
def prva_vrstica(ime_datoteke): '''Vrne prvo vrstico datoteke (brez znaka za prehod v novo vrsto) Če je datoteka prazna, kot rezultat vrnemo prazen niz ''' dat = open(ime_datoteke) vrst = dat.readline() vrst = vrst.rstrip() # odstranimo znak za novo vrsto dat.close() return vrst def prva_vrstica_V1(ime_datoteke): ''' Funkcija vrne prvo vrstico iz datoteke Če je datoteka prazna, kot rezulat vrnemo prazen niz ''' dat = open(ime_datoteke, 'r') vrst = dat.readline() dat.close() return vrst[:-1] # odstranimo znak za novo vrsto def prva_vrstica_V2(ime_datoteke): '''Vrne prvo vrstico datoteke (brez znaka za prehod v novio vrsto) Predpostavka: Datoteka ni prazna! ''' # uporabimo nekaj drugačnih prijemov - razmisli o njih! with open(ime_datoteke) as f: return f.readlines()[0].rstrip()
Sestavite funkcijo stevilo_dolgih_vrstic(ime_datoteke, dolz)
, ki vrne število
vseh vrstic v datoteki z danim imenom, ki so dolge vsaj dolz
znakov
(pri tem je dolz
-ti lahko tudi znak "\n"
za novo vrstico).
def stevilo_dolgih_vrstic(ime_datoteke, dolz): '''vrne število vrstic v datoteki, ki so dolge vsaj dolz znakov Zraven štejemo tudi prehod v novoi vrsto''' kolikoJihJe = 0 for vrs in open(ime_datoteke): # gremo po vseh vrsticah datoteke if len(vrs) >= dolz : kolikoJihJe += 1 return kolikoJihJe def stevilo_dolgih_vrstic_V1(ime_datoteke, dolz): '''vrne število vseh vrstic v datoteki, ki so dolge vsaj dolz znakov ''' stVrstic = 0 for vrstica in open(ime_datoteke, 'r'): # prečešemo vse vrstice v datoteki # ali so dovolj dolge if len(vrstica) >= dolz: stVrstic += 1 return stVrstic def stevilo_dolgih_vrstic_V2(ime_datoteke, dolz): '''vrne število vrstic v datoteki, ki so dolge vsaj dolz znakov Zraven štejemo tudi prehod v novo vrsto''' # uporabimo nekaj drugačnih prijemov - razmisli o njih! with open(ime_datoteke) as f: return len([vrs for vrs in f if len(vrs) >= dolz])
Sestavite funkcijo najdaljsa_vrstica(ime_datoteke)
, ki vrne najdaljšo
vrstico v datoteki z danim imenom. Če je takih vrstic več, vrni zadnjo!
def najdaljsa_vrstica(ime_datoteke): ''' vrne najdaljšo vrstico v datoteki z danim imenom. ''' najdVrst = '' najDolz = 0 for vrst in open(ime_datoteke): dolTrenutne = len(vrst) if dolTrenutne >= najDolz: #boljši kandidat! = ker hočemo zadnjo! najdVrst = vrst najDolz = dolTrenutne return najdVrst.rstrip() def najdaljsa_vrstica_V2(ime_datoteke): ''' vrne najdaljšo vrstico v datoteki z danim imenom. ''' # uporabimo nekaj drugačnih prijemov - razmisli o njih! with open(ime_datoteke) as f: _, max_vrs = max((len(vrs), vrs) for vrs in f) return max_vrs.rstrip()
Sestavi funkcijo prestejVrstice(datoteka)
, ki prešteje, koliko vrstic je na
dani znakovni datoteki. Funkcija naj za parameter dobi ime datoteke.
def prestejVrstice(datoteka): ''' koliko vrstic je na dani znakovni datoteki prepostavimo, da je datoteka dovolj kratka, da lahko vse njene vrstice shranimo v seznam ''' f = open(datoteka,'r') stVrstic = len(f.readlines()) f.close() return stVrstic def prestejVrstice_V1(datoteka): ''' koliko vrstic je na dani znakovni datoteki''' # ta rešitev deluje, tudi, če je datoteka zelooooooo dolga stVrstic = 0 for vrst in open(datoteka) : # preko vseh vrstic stVrstic += 1 return stVrstic
Sestavi funkcijo vrniKVrstico(datoteka,k)
, ki vrne k-to vrstico dane znakovne datoteke.
Vrednost k in ime datoteke naj funkcija dobi za parameter.
V primeru ko datoteka ne vsebuje dovolj vrstic, naj vrne prazen niz.
def vrniKVrstico(datoteka,k): ''' vrne k-to vrstico dane datoteke ''' kolikoŠe = k # koliko vrstic je še potrebno prebrati f = open(datoteka,'r') while kolikoŠe > 0: vrstica = f.readline() if vrstica == '': # smo že čez konec datoteke, vrstic je premalo f.close() return '' kolikoŠe -= 1 # ena manj za prebrati f.close() return vrstica def vrniKVrsticoV2(datoteka,k): ''' vrne k-to vrstico dane datoteke ''' # če imamo dovolj prostora f = open(datoteka,'r') vrstice = f.readlines() f.close() if len(vrstice) >= k: # imamo dovolj vrstic return vrstice[k - 1] return ""
Na datoteki je pesem zapisana po kiticah.
To pomeni, da so med kiticami prazne vrstice. Sestavi
funkcijo odstraniPrazneVrstice(datotekaV, datotekaI)
, ki bo
za dano ime datoteke datotekaV
vse kitice združila in jih izpisala na
datoteko2.
Dekle je po vodo šlo
na visoke planine.
Vodo je zajemala,
je ribico zajela.
Ribica jo je prosila:
oj, pusti me živeti.
Dekle b'la je usmiljena,
je ribico spustila.
Ribica je zaplavala,
je dekle poškropila.
Dekle je po vodo šlo
na visoke planine.
Vodo je zajemala,
je ribico zajela.
Ribica jo je prosila:
oj, pusti me živeti.
Dekle b'la je usmiljena,
je ribico spustila.
Ribica je zaplavala,
je dekle poškropila.
def odstraniPrazneVrstice(datotekaV, datotekaI): '''Izpiše datoteko brez praznih vrstic''' f = open(datotekaV,'r') izpis = open(datotekaI, 'w') while True: trenutnaVrstica = f.readline() if trenutnaVrstica not in ['\n', '\r\n']: # različni načini (glede na OS) oblike prazne vrstice print (trenutnaVrstica,end='',file=izpis) if trenutnaVrstica == '': # smo že čez konec datoteke f.close() izpis.close() return def odstraniPrazneVrstice_V1(datotekaV, datotekaI): '''Izpiše datoteko brez praznih vrstic''' izpis = open(datotekaI, 'w') for vrstica in open(datoteka): if vrstica != '\n' : # ni prazna print(vrstica, end='', file=izpis) izpis.close()
Direktor podjetja je dobil datoteko priporocilo.txt
na kateri je pisalo:
Spoštovani gospod direktor,
Janeza Novaka, mojega asistenta pri delu, vedno vidite, kako
trdo dela v svoji mali pisarni. Janez dela neodvisno in ne
lenari ali se pogovarja s sodelovci. Nikoli se ne zgodi, da bi
zavrnil kakšnega sodelovca, ki potrebuje pomoc. Do sedaj je vedno
koncal z delom pravocasno. Zelo pogosto si vzeme podaljšan
delovni cas, da konca svoje delo, pri cemer vcasih preskoci
odmor. Janez je takšen delavec, ko nima absolutno nobenega
spodrslajaja pri opravljenih delih, ima visoke dosežke in je širokega
znanja na njegovem podrocju. Moje mnenje je, da ga lahko takoj
uvrstimo med tiste najbolj vzorne delovce, ki jih nikoli ne
odpustimo. Prav tako vam vljudno predlagam, da je moj predlog
o napredovanju tega izjemnega, vzornega in nepogrešljivega delavca
izvršen kakor hitro je mogoce.
Lep pozdrav!
Že se je spravil pisati predlog za napredovanje, ko je po e-pošti prispel dopis:
Direktor!
Ta idiot je stal za menoj, ko sem pisal prejšnje priporocilo.
Prosim znova preberite vsako drugo vrstico tega pisma.
Direktor je sedaj povsem zmeden. Pomagaj mu in sestavi funkcijo
izpisiDrugo(datotekaV, datotekaI)
, ki na datotekoI
izpiše vsako drugo vrstico
vsebine datoteke datotekaV
!
def izpisiDrugo(datotekaV, datotekaI): '''izpiše vsako drugo vrstico datoteke ''' f = open(datotekaV) izp = open(datotekaI, 'w') vrstica = " " # zelimo zaceti pri prvi vrstici while vrstica != '' : # do konca datoteke vrstica = f.readline() # ta je liha, zato jo izpišemo print(vrstica, end= '', file = izp) # ker že vsebuje \n # naslednjo preskočimo vrstica = f.readline() f.close() izp.close() def izpisiDrugoV1(datotekaV, datotekaI): '''izpiše vsako drugo vrstico datoteke ''' stVrstice = 1 izp = open(datotekaI, 'w') for vrstica in open(datoteka): if stVrstice % 2 == 1 : # vsako drugo preskočimo, začnemo s prvo print(vrstica, end= '', file = izp) # ker že vsebuje \n stVrstice += 1 izp.close() def izpisiDrugoV2(datoteka): ''' Če vemo, da je dovolj prostora, bomo uporabili kar readlines ''' f = open(datoteka) vrstice = f.readlines() izp = open(datotekaI, 'w') # iz seznama vzamemo vsako drugo vrstice = vrstice[::2] for vrstica in vrstice: # Sedaj pa jih le še izpišemo print(vrstica, end= '', file = izp) # ker že vsebuje \n def izpisiDrugoV3(datoteka): ''' In še malo bolj kompaktno ''' for vrstica in open(datoteka).readlines()[0:-1:2]: print(vrstica, end= '', file = izp) # ker že vsebuje \n izp.close()
Arheologi: Arheologi so v jami blizu Gize našli čuden papirus.
Besedilo na njem je bilo videti zelo čudno, a po drugi strani zelo podobno
našemu. Dolgo so poskušali vse, da bi ga razvozlali. Na koncu se je oglasil
6 letni Mihec, sin glavnega arheologa: "Oci, zakaj si pa na ta papir pisal v napačno smer?"
In res. Šlo je za povsem običajni tekst, le besedilo je bilo zapisano od desne proti levi.
Ker pa je tako besedilo malček zoprno brati, pomagaj arheologom in sestavi funkcijo arheologi(datoteka)
,
ki za dano ime datoteke sestavi novo datoteko z ravno obrnjenim imenom in enako koncnico
(iz bla.txt
torej naredi alb.txt
, iz mojaDat.py
pa taDajom.py
). Ta nova datoteka
naj vsebuje ravno obrnjene vrstice prvotne datoteke.
import os.path def arheologi(datoteka): '''sestavimo novo datoteko z ravno obrnjenim imenom in enako koncnico Ta nova datoteka vsebuje ravno obrnjene vrstice prvotne datoteke.''' #locimo koncnico datotek od imena ime, koncnica = os.path.splitext(datoteka) #ime datoteke obrnemo imeDat = ime[::-1] #ustvarimo novo datoteko z obrnjenim imenom novaDat = open(imeDat + koncnica,"w") for vrstica in open(datoteka,"r"): obVrstica = vrstica.rstrip()[::-1] # zraven se še znebimo zadnjega znaka print(obVrstica, file = novaDat) novaDat.close()
Tina za vsak obrok, ki ga poje, zapiše njegovo kalorično vrednost (celo število). Vse te podatke hrani v datoteki: podatke vsakega dne zapiše v svojo vrstico, znotraj vrstice pa jih loči z vejico.
Sestavite funkcijo kalorijeNaDan(datoteka)
, ki kot parameter dobi ime
vhodne datoteke in vrne seznam kalorij, ki jih je Tina dnevno zaužila.
Torej, za vsako vrstico v datoteki (ki predstavlja en dan) dodaj v seznam eno število, ki naj bo enako vsoti kalorij za tisti dan.
def skupneKalorije(niz): '''sešteje cela števila v nizu, ki so ločena z vejico''' tabelaNizov = niz.split(',') skupnaVsota = 0 for elt in tabelaNizov: skupnaVsota += int(elt) # ne pozabi pretvoriti niza v število! return skupnaVsota def kalorijeNaDan(datoteka): '''Seznam kalorij, zaužitih na posamezni dan''' zaužiteKalorije = [] for vrstica in open(datoteka): # uporabimo zgornjo funkcijo, ki "obdela" vrstico in seštejemo naTaDan = skupneKalorije(vrstica) zaužiteKalorije.append(naTaDan) return zaužiteKalorije
Sestavite funkcijo vsotaKalorij(vhod, izhod)
, ki kot argumenta dobi
imeni dveh datotek: vhodno (ta vsebuje Tinine zapiske) in izhodno. Na
izhodno datoteko naj za vsako vrstico v vhodni datoteki zapiše vsoto
kaloričnih vrednosti zaužite hrane tistega dne. Vsako število v izhodni
datoteki naj bo v svoji vrstici.
def vsotaKalorij(vhod, izhod): '''za vsako vrstico v vhodni datoteki zapiše vsoto na izhodno datoteko''' piši = open(izhod, 'w') for vrstica in open(vhod): vsota = skupneKalorije(vrstica) # izračuna vsoto števil v vrstici piši.write(str(vsota) + '\n') piši.close()
Sestavite funkcijo povprecjeKalorij(vhod, izhod)
, ki kot argumenta dobi
imeni dveh datotek: vhodno in izhodno. Na izhodno datoteko naj za vsako
vrstico na vhodni datoteki zapiše zaporedno številko vrstice (vrstice se
začno šteti z ena) ter povprečno kalorično vrednost obrokov, ki jih je
Tina zaužila tisti dan, na dve decimalni mesti natančno. V zadnjo (dodatno)
vrstico pa naj funkcija zapiše dnevno povprečje zaužitih kalorij (prav
tako na dve decimalni mesti natančno).
def vrniKalorije(niz): '''iz niza, v katerem so števila ločena z vejicami, vrne seznam teh celih števil.''' tabelaNizov = niz.split(',') izhTabela = [] for elt in tabelaNizov: izhTabela.append(int(elt)) # dodamo število, ki ga dobimo iz niza return izhTabela # lahko bi vse skupaj napisali tudi v eni vrstici # return list(map(int, niz.split(','))) def povprecjeKalorij(vhod,izhod): vsotaKalorij = 0 steviloDni = 0 piši = open(izhod, "w") for vrstica in open(vhod): obroki = vrniKalorije(vrstica) dnevniVnos = sum(obroki) steviloDni += 1 vsotaKalorij += dnevniVnos print("{0} {1:.2f}".format(steviloDni, dnevniVnos / len(obroki)), file=piši) # še končni podatek o povprečju print("{0:.2f}".format(vsotaKalorij / steviloDni), file=piši) piši.close()
V datoteki imamo zapisane podatke o vrednosti neke delnice. V vsaki vrstici je zapisan podatek v obliki
YYYY-MM-DD,vrednost
kjer je prvi podatek dan, drugi pa vrednost delnice na ta dan.
Sestavite funkcijo preberi(ime_datoteke)
, ki kot parameter sprejme
ime datoteke, vrne par nabor dveh seznamov, v prvem naj bodo datumi
(kot nizi), v drugem pa vrednosti delnice (kot realna števila).
def preberi(ime_datoteke): '''vrne par (nabor) dveh seznamov, v prvem so datumi (kot nizi), v drugem pa vrednosti delnice (kot realna števila). ''' datumi = [] vrednosti = [] for vrstica in open(ime_datoteke,'r'): v = vrstica.strip().split(',') # prvi podatek je datum, drugi vrednost datumi.append(v[0]) # datum dodamo nespremenjen vrednosti.append(float(v[1])) return (datumi, vrednosti)
Logaritemski povratek delnice je definiran kot logaritem kvocienta
vrednosti delnice za dva zaporedna dneva trgovanja.
Zakaj je to uporabno
Sestavite funkcijo
povratek(imeDat)
, ki kot parameter sprejme ime datoteke z vrednostmi delnice
in vrne seznam logaritemskih povratkov. Če je
podana datoteka prazna ali pa vsebuje le en podatek, naj funkcija vrne prazen
seznam.
from math import log def povratek(ime_datoteke): '''Vrne seznam logaritemskih popravkov''' datumi, vrednosti = preberi(ime_datoteke) povratki = [] for i in range(1,len(vrednosti)): #začnemo pri drugem dnevu povratki.append(log(vrednosti[i]/vrednosti[i-1])) return povratki
Iz logaritemskih povratkov lahko razberemo, ali je vrednost delnice
naraščala ali padala. Sestavite funkcijo trend(povratki)
, ki sprejme
seznam logaritemskih povratkov in vrne niz pozitiven trend
, če je
v seznamu več pozitivnih vrednosti kot negativnih, sicer pa naj vrne
negativen trend
. Vrednosti 0 štejte k negativnim.
def trend(povratki): '''Vrne niz "pozitiven trend", če je v seznamu logaritemskih povratkov več pozitivnih vrednosti kot negativnih, sicer pa "negativen trend"''' poz = 0 neg = 0 for x in povratki: if x > 0: poz += 1 else: neg += 1 if poz > neg: return 'pozitiven trend' else: return 'negativen trend'
Letna volatilnost
delnice (Volatilnost ali nihajnost označuje, koliko je statistično verjetno, da
cena delnice v kratkem času močneje zraste ali pade)
je definirana kot večkratnik standardnega
odklona logaritemskega povratka:
volatilnost(ime_datoteke)
, ki iz datoteke prebere
vrednosti delnice in vrne njeno letno volatilnost
from math import sqrt def volatilnost(ime): ''' iz datoteke prebere vrednosti delnice in vrne njeno letno volatilnost''' p = povratek(ime) n = len(p) mu = sum(p)/n # povprečna vrednost logaritemskih povratkov s2 = 0 for x in p: s2 += (x-mu)**2 return sqrt(252 * s2/n)
Sestavite funkcijo html2txt(vhod, izhod)
, ki bo vsebino datoteke z
imenom vhod
prepisala v datoteko z imenom izhod
, pri tem pa odstranila
vse značke. Vemo, da je datoteka HTML sestavljena prav!
Značke se začnejo z znakom <
in končajo z znakom >
. Pozor: Začetek in
konec značke nista nujno v isti vrstici. Takrat se vrstica nadaljuje!
Prav tako ima lahko značka lastnosti, npr. značka a
ima lastnost href
<a href = "kk.htm">
Na primer, če je v datoteki vreme.html
zapisano:
<h1>Napoved vremena</h1>
<p>Jutri bo <i><b>lepo</b></i> vreme.
Več o vremenu preberite <a
href="napoved.html">tukaj</a>.</p>
bo po klicu html2txt('vreme.html', 'vreme.txt')
v datoteki vreme.txt
zapisano (pozor na tretjo vrstico!):
Napoved vremena
Jutri bo lepo vreme.
Več o vremenu preberite tukaj.
def html2txt(vhod, izhod): ''' Funkcija vsebino datoteke z imenom vhod prepiše v datoteko z imenom izhod, pri tem pa odstrani vse značke za HTML. ''' html = open(vhod) txt = open(izhod, 'w') znotrajZnačke = False # ali se nahajamo v notranjosti for vrstica in html: izhodnaVrstica = '' for znak in vrstica: if znak in '<>': # če smo naleteli na začetek ali na konec značke znotrajZnačke = not znotrajZnačke else: # gre za nek drug znak if not znotrajZnačke : # če nismo v znački, znak dodamo izhodnaVrstica += znak txt.write(izhodnaVrstica) html.close() txt.close()
Sestavite funkcijo tabela(vhod, izhod)
, ki bo podatke iz vhodne
datoteke zapisala v obliki HTML tabele v izhodno datoteko.
V vhodni datoteki so podatki shranjeni po vrsticah ter ločeni z vejicami.
Na primer, če je v datoteki tabela.txt
zapisano:
ena,dva,tri
17,52,49.4,6
abc,xyz
bo po klicu tabela('tabela.txt', 'tabela.html')
v datoteki tabela.html
:
<table>
<tr>
<td>ena</td>
<td>dva</td>
<td>tri</td>
</tr>
<tr>
<td>17</td>
<td>52</td>
<td>49.4</td>
<td>6</td>
</tr>
<tr>
<td>abc</td>
<td>xyz</td>
</tr>
</table>
Pozor: Pazi na zamik (število presledkov na začetku vrstic) v izhodni datoteki.
def tabela(ime_vhodne, ime_izhodne): ''' zapis podatkov iz CSV datoteko v datoteko HTML v obliki tabele''' # naučimo se uporabljati stavek with! Tu ni uporabe metode close! with open(ime_vhodne) as vhodna: with open(ime_izhodne, 'w') as izhodna: print('<table>', file=izhodna) # začetek tabele for vrstica in vhodna: print(' <tr>', file=izhodna) # vska vrstica se začne z glavo vrstica = vrstica.strip() # znebimo se uvodnih in končnih 'belih' znakov podatki = vrstica.strip().split(',') #ločilni znak med podatki je vejica for podatek in podatki: # posamezni stolpci print(' <td>{0}</td>'.format(podatek), file=izhodna) print(' </tr>', file=izhodna) # konec vrstice print('</table>', file=izhodna) # konec tabele
Sestavite funkcijo seznami(vhod, izhod)
, ki bo podatke iz vhodne
datoteke zapisala v izhodno datoteko v obliki neurejenega seznama. V
vhodni datoteki se vrstice seznamov začnejo z zvezdico.
Na primer, če je v datoteki seznami.txt
zapisano:
V trgovini moram kupiti:
* jajca,
* kruh,
* moko.
Na poti nazaj moram:
* obiskati sosedo.
bo po klicu seznami('seznami.txt', 'seznami.html')
v datoteki seznami.html
:
V trgovini moram kupiti:
<ul>
<li>jajca,</li>
<li>kruh,</li>
<li>moko.</li>
</ul>
Na poti nazaj moram:
<ul>
<li>obiskati sosedo.</li>
</ul>
def seznami(ime_vhodne, ime_izhodne): '''Seznam na tekstovni datoteki prepišimo kot naštevni seznam v HTML''' seznam = False # ali smo znotraj obstoječega seznama vhodna = open(ime_vhodne) izhodna = open(ime_izhodne, 'w') for vrstica in vhodna: if vrstica[0] == '*': # z * so označeni elementi seznama if not seznam: # gre za nov seznam, zato ga ustvarimo! print('<ul>', file=izhodna) seznam = True print(' <li>{0}</li>'.format(vrstica[2:-1]), file=izhodna) # znebimo se uvodne * s presledkom, in \n s konca else: #'navadna vrstica' if seznam: # je potrebno zaključiti seznam? print('</ul>', file=izhodna) seznam = False print(vrstica, file=izhodna, end='') if seznam: print('</ul>', file=izhodna) # če je zadnji seznam šel do konca datoteke! vhodna.close() izhodna.close()
Sestavite funkcijo gnezdeni_seznami(vhod, izhod)
, ki bo podatke iz
vhodne datoteke zapisala v izhodno datoteko v obliki neurejenega gnezdenega
seznama. V vhodni datoteki je vsak element seznama v svoji vrstici, zamik
pred elementom pa določa, kako globoko je element gnezden.
Na primer, če je v datoteki seznami.txt
zapisano:
živali
sesalci
slon
ptiči
sinička
rastline
sobne rastline
difenbahija
bo po klicu gnezdeni_seznami('seznami.txt', 'seznami.html')
v datoteki
seznami.html
zapisano:
<ul>
<li>živali
<ul>
<li>sesalci
<ul>
<li>slon
</ul>
<li>ptiči
<ul>
<li>sinička
</ul>
</ul>
<li>rastline
<ul>
<li>sobne rastline
<ul>
<li>difenbahija
</ul>
</ul>
</ul>
Značk <li>
ne zapirajte.
def gnezdeni_seznami(ime_vhodne, ime_izhodne): '''iz "navadnega" gnezdenega seznama naredimo tak seznam v HTML''' nivo = 0 zamik = 2 # naučimo se uporabljati stavek with! Tu ni uporabe metode close! with open(ime_vhodne) as vhodna: with open(ime_izhodne, 'w') as izhodna: for vrstica in vhodna: # izračunaj na katerem nivoju sem # poiskati moramo prvi znak, ki ni presledek prviZnak = 0 for i in range(len(vrstica)): if vrstica[i] != ' ': break # našli smo ga prviZnak += 1 # ga še ni n = prviZnak // zamik + 1 # račun nivoja vrstica = vrstica.strip() #sedaj se lahko znebimo začetnih in končnih 'belih znakov' if n > nivo: # je potrebno začetni novo gnezdenje? print(2 * zamik * nivo * ' ' + '<ul>', file=izhodna, sep="") nivo += 1 while n < nivo: # končamo gnezdenje nivo -= 1 print(2 * zamik * nivo * ' ' + '</ul>', file=izhodna, sep="") print((2 * zamik * nivo - zamik) * ' ' + '<li>', vrstica, file=izhodna, sep="") while nivo > 0: # še končen zaključek gnezdenja nivo -= 1 print(2 * zamik * nivo * ' ' + '</ul>', file=izhodna, sep="")
Na vsakem zanimivem igrišču za golf so ovire: jezero, pesek, ...
Jezero
je krog, podan kot trojica (x,y,r)
.
Pesek
je pravokotnik, podan kot četverica(x1,y1,x2,y2)
. Predpostaviš lahko, da
so to po vrsti koordinate levega spodnjega in desnega zgornjega oglišča.
Vse koordinate računamo na tri decimalke (round(x, 3)
)
Na datoteki imamo zapisane podatke o posameznih udarcih v obliki polarnih koordinat.
V vsaki vrstici sta zapisani celi števili r
in f
, ločeni s presledkom.
Napišite metodo datotekaPolozajev(vhod, izhod)
, ki naj datoteko prebere in v tvori novo datoteko tako,
da je v vsaki vrstici
zapisan njen trenutni položaj (v obliki decimalnih števil, zaokroženih na 3 decimalna mesta)
in ločenih s presledkom. V ta namen uporabite formatiranje s pomočjo "{0:.3f}".format(x)
Začetni položaj naj bo v točki (0,0)
.
from math import * def datotekaPolozajev(vhod, izhod): '''Iz seznama udarcev, podanih v polarnih koordinatah, na datoteko zapiše kartezične koordinate položaja točk''' x,y = 0,0 g = open(izhod, "w") for vrstica in open(vhod): polarnekoordinate = vrstica.strip('\n').split(' ') r = int(polarnekoordinate[0]) fi = int(polarnekoordinate[1]) x += r * cos(fi * pi / 180) y += r * sin(fi * pi / 180) print("{0:.3f}".format(x), "{0:.3f}".format(y), file=g) g.close()
Podan je seznam položajev žogic po posameznem udarcu in seznam, katerega vsak element
je nabor, ki podaja jezero ali pesek. Napišite metodo seIzogne(pot, ovire)
, ki pove, ali
se pot v celoti izogne oviram. Pazi: jezero je podano z naborom treh, pesek pa z naborom štirih števil.
Najprej napišite metodi jeVJezeru(zogica, jezero)
in jeVPesku(zogica, pesek)
, ki
povesta, ali je žogica v jezeru ali v pesku. Žogica je podana kot par (x,y)
, torej "nima dimenzije".
def jeVJezeru(zogica, jezero): '''Ali je zogica znotraj jezera ''' (x0,y0) = zogica (x,y,r) = jezero # okroglo jezero return round((x-x0)**2 + (y-y0)**2,3) <= round(r**2, 3) def jeVPesku(zogica, pesek): '''Ali je zogica znotraj peska ''' (x0,y0) = zogica (xmin,ymin,xmax,ymax) = pesek # prakokotna peščena ovira return (xmin <= x0 <= xmax) and (ymin <= y0 <= ymax) def seIzogne(pot, ovire): '''Ali se žogice, katerih položaji so podani v seznamu pot izogne vsem oviram, podanih v seznamu ovire''' for tocka in pot: # za vsak položaj preverimo, če smo naleteli na kakšno oviro for ovira in ovire: if (len(ovira)==3 and jeVJezeru(tocka, ovira)): # žogica se znajde v jezeru return False if (len(ovira)==4 and jeVPesku(tocka, ovira)): # žogica se znajde v peščeni oviri return False return True
Napišite metodo kjeJeZogica(datoteka, zacetek, ovire)
, ki
vrne vektor od začenega do končnega položaja ali None,
če žogica kdaj vmes pade v oviro.
Posamezni udarci so v polarnih koordinatah zapisani na datoteko, začetek pa je
podan kot par (x,y)
.
def kjeJeZogica(datoteka, zacetek, ovire): '''Glede na seznam udarcev, podanem na datoteki datoteka, seznama ovir (seznam naborov) in začetnega položaja žogice ugotovi vektor od začetnega do končnega položaja žogice. Če žogica pristane v oviri, vrni None''' x,y = zacetek pot = [] pot.append((x,y)) # sestavimo seznam položajev žogice for vrstica in open(datoteka): polarnekoordinate = vrstica.strip('\n').split(' ') r = int(polarnekoordinate[0]) fi = int(polarnekoordinate[1]) x += r * cos(fi * pi / 180) y += r * sin(fi * pi / 180) pot.append((round(x,3),round(y,3))) # na koncu je žogica v (x, y) # uporabimo funkcijo prejšnje naloge if not seIzogne(pot, ovire): return None else: return (round(x-zacetek[0], 3),round(y-zacetek[0],3))
besede, besede ... Kaj sploh je beseda? Osnovni delček komunikacije? Orožje? Zaporedje črk? Za nas bo beseda poljubno zaporedje znakov, torej niz!
Sestavi funkcijo podobna(beseda, sezBesed)
, ki kot argument sprejme besedo in kot rezultat vrne
prvo med tistimi besedami iz sezBesed
, v kateri se pojavi čim več črk, ki se pojavijo tudi v dani
besedi. Teh črk je seveda lahko tudi 0 ;-) !Vsako ujemajočo se črko štejemo le enkrat, tudi če se v obeh besedah pojavi večkrat.
Funkcija naj deluje tako, da ne razlikuje med malimi in velikimi črkami.
Če take sploh besede ni, vrni None
.
>>> besede = ["ana", "berta", "cilka", "dani", "ema", "fanči", "greta", "hilda"]
>>> podobna("merjasec", besede)
'berta'
>>> podobna("zmaj", besede)
'ema'
>>> podobna("Krava", besede)
'berta'
Ana
in krava
se ujemata v eni črki, namreč črki a
in ne v dveh, pa čeprav imata po dva a
-ja (tudi če
bi napisali ana
).
Opomba: vsaka podobnost med Berto
in merjascem
je zgolj naključna.
def podobna(beseda, sezBesed): '''Katera beseda v sezBesed ima največ skupnih črk z besedo `beseda`''' beseda = beseda.lower() bs = set(beseda) # množica vseh črk (različnih seveda ;-) ) naj_crk = -1 najBeseda = None # nimamo še najboljše besede for enaBeseda in sezBesed: skupnih = len(bs & set(enaBeseda.lower())) # velikost preseka mniožic if skupnih > naj_crk: # smo našli boljšega kandidata? naj_crk = skupnih najBeseda = enaBeseda return najBeseda
Napiši funkcijo najraznolika(bes)
, ki kot argument prejme neprazen seznam nizov in kot rezultat
vrne niz, ki ima največ različnih znakov. Male in velike črke upoštevaj kot iste znake - beseda
"MamA" ima samo dva različna znaka. Če obstaja več besed z enakim številom različnih znakov,
naj vrne zadnjo (glede na položaj v seznamu) med njimi.
>>> besede = ["RABarbara", "izpit", "zmagA"]
>>> najraznolika(besede)
zmagA
def najraznolika(sezBesed): '''Kateri niz v sezBesed ima največ različnih znakov''' najZnakov = 0 for enNiz in sezBesed: crk = len(set(enNiz.lower())) # število različnih znakov if crk >= najZnakov: # boljši kandidat (= ker hočemo zadnjega!) najZnakov = crk najNiz = enNiz return najNiz
Dan je seznam besed. Napiši funkcijo sameRazličneČrke(sezBesed)
, ki vrne urejen (kot ureja sorted
)
seznam tistih besed, ki imajo vse črke različne. Pri tem upoštevaj le črke angleške abecede!
Male in velike črke razlikujemo! Vsako besedo upoštevaj le enkrat.
Morda prav pride
>>> import string
>>> string.ascii_letters
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
Zgled uporabe funkcije
>>> besede = ["Rabarbara", "kralj", "Kok", "čmrlj!!", "11-isto", "zmaga", "kralj", "konec"]
>>> sameRazličneČrke(besede)
['11-isto', 'Kok', 'konec', 'kralj', 'čmrlj!!']
def ohraniČrke(niz): '''vrne niz, ki vsebuje le še črke angleške abecede. ''' import string vseČrke = set(string.ascii_letters) novNiz = "" for znak in niz: if znak in vseČrke: # črka angleške abesede novNiz += znak return novNiz def sameRazličneČrke(sezBesed): '''vrne po abecedi urejen seznam tistih besed, ki imajo vse črke različne.''' množicaNovih = set() for beseda in sezBesed: oklBeseda = ohraniČrke(beseda) crk = len(set(oklBeseda)) # število različnih znakov if crk >= len(oklBeseda): # različnih črkl je toliko kot vseh množicaNovih.add(beseda) novSeznam = list(množicaNovih) # iz množice v seznam return sorted(novSeznam)
Program
import urllib.request
naslov = "http://splasho.com/upgoer5/phpspellcheck"
naslov += "/dictionaries/1000.dicin"
vir = urllib.request.urlopen(naslov)
for vr in vir:
vrstica = vr.decode()
print(vrstica, end='')
izpiše po abecedi urejenih 1000 najpogostejših angleških besed
Napiši funkcijo najraznolikaAngBeseda()
, ki vrne po abecedi urejen seznam vseh
tistih med temi 1000 najpogostejšimi angleškimi besedami, ki imajo največ različnih črk.
def najraznolikaAngBeseda(): '''Katere med pogostimi angl. besedami imajo največ različnih znakov''' import urllib.request naslov = "http://splasho.com/upgoer5/phpspellcheck" naslov += "/dictionaries/1000.dicin" vir = urllib.request.urlopen(naslov) najZnakov = 0 for beseda in vir: enNiz = beseda.decode()[:-1] # odstranimo \n crk = len(set(enNiz.lower())) # število različnih znakov if crk == najZnakov: # enakovredni kandidat najZnakov = crk najNizi.append(enNiz) elif crk > najZnakov: # boljši kandidat najZnakov = crk najNizi = [enNiz] return najNizi # urejanje ni potrebno, ker so že besede urejene
Napiši funkcijo vse_crke(beseda, črke), ki pove, ali množica crke vsebuje vse črke, ki se pojavijo v podani besedi. Pri tem sme množica vsebovati tudi črke, ki se v besedi ne pojavijo.
>>> vse_crke("AMFITEATER", set(["A", "M"]))
False
>>> vse_crke("AMFITEATER", set(["A", "M", "F", "I", "T", "E"]))
False
>>> vse_crke("AMFITEATER", set(["A", "M", "F", "I", "T", "E", "R"]))
True
>>> vse_crke("AMFITEATER", set(["A", "M", "F", "I", "T", "E", "R", "X",
"O", "B", "L"]))
True
def vse_crke(beseda, črke): '''Ali množica črke vsebuje vse črke, ki se pojavijo v besedi''' return not (set(beseda) - set(črke))
Naloga sposojena od tu in malček predelana.
Program
import urllib.request
naslov = "http://lokar.fmf.uni-lj.si/JAVNO/samostalniki.txt"
vir = urllib.request.urlopen(naslov)
vse = vir.read().decode()
print(vse[:297])
izpiše prvih nekaj samostalnikov, ki so na datoteki na ustreznem naslovu
Sestavi funkcijo vrniSamostalnik(n)
, ki vrne n-ti samostalnik iz te datoteke.
Če je n npr. 1012 in je na datoteki le 300 samostalnikov, dobimo 112 tega.
>>> vrniSamostalnik(1)
DOGODEK
def vrniSamostalnik(n): '''vrne n-ti samostalnik z datoteke''' import urllib.request naslov = "http://lokar.fmf.uni-lj.si/JAVNO/samostalniki.txt" vir = urllib.request.urlopen(naslov) vse = vir.read().decode() samostalniki = vse.split() koliko = len(samostalniki) return samostalniki[(n - 1) % koliko]
Napiši funkcijo kjeJeZnak(beseda, znak)
, ki vrne urejen seznam mest v besedi
beseda
, na katerih nastopa podana črka znak
. Funkcija naj ne izpisuje ničesar, le rezultat naj vrača!
>>> kjeJeZnak("PONUDNIK","N")
[2, 5]
>>> kjeJeZnak("RABARBARA", "R")
[0, 4, 7]
>>> kjeJeZnak("AMFITEATER", "O")
[]
def kjeJeZnak(beseda, crka): '''seznam indeksov, kjer v besedi nastošpa črka''' mesta = [] for i in range(len(beseda)): if beseda[i] == crka: mesta.append(i) return mesta # krajša rešitev z izpeljanimi seznami - preštudiraj! def kjeJeZnak(beseda, crka): '''seznam indeksov, kjer v besedi nastošpa črka''' return [i for i, c in enumerate(beseda) if c==crka]
Napiši funkcijo imaVseZnake(beseda, znaki), ki pove, ali množica znaki vsebuje vse črke, ki se pojavijo v besedi beseda. Opomba: množica sme vsebovati tudi črke, ki se v besedi ne pojavijo.
>>> imaVseZnake("AMFITEATER", {"A", "M"})
False
>>> imaVseZnake("AMFITEATER", {"A", "M", "F", "I", "T", "E"})
False
>>> imaVseZnake("AMFITEATER", {"A", "M", "F", "I", "T", "E", "R"})
True
>>> imaVseZnake("AMFITEATER", {"A", "M", "F", "I", "T", "E", "R", "X", "O", "B", "L"})
True
def imaVseZnake(beseda, crke): '''ali množica znaki vsebuje vse črke, ki se pojavijo v besedi beseda''' for c in beseda: if not c in crke: return False return True # z množicami gre enostavneje def imaVseZnake(beseda, crke): '''ali množica znaki vsebuje vse črke, ki se pojavijo v besedi beseda''' return set(beseda) <= crke
Napiši funkcijo pokaziZnake(beseda, znaki), ki kot argument sprejme besedo beseda in množico (set) črk znaki. Funkcijo mora vrniti besedo, v kateri so vse črke, ki ne nastopajo v množici znaki, spremenjene v pike.
>>> pokaziZnake("PONUDNIK", {"O", "N"})
'.ON..N..'
>>> pokaziZnake("PONUDNIK", {"O", "I", "K"})
'.O....IK'
>>> pokaziZnake("PONUDNIK", set())
'........'
>>> pokaziZnake("PONUDNIK", {"P", "O", "N", "I", "K", "U"})
'PONU.NIK'
def pokaziZnake(beseda, crke): "vrne besedo, v kateri so vse črke, ki ne nastopajo v množici znaki, spremenjene v pike." bes = "" for c in beseda: if c in crke: bes += c else: bes += "." return bes # z izpeljanimi seznami gre tudi v eni vrstici ... def pokaziZnake(beseda, crke): "vrne besedo, v kateri so vse črke, ki ne nastopajo v množici znaki, spremenjene v pike." return "".join([c if c in crke else "." for c in beseda])
Napiši igro "vislice". Pri tem uporabljajte funkcije, ki ste jih napisali prej. Igra poteka tako, da računalnik izbere naključno besedo iz datoteke s samostalniki. Nato izpisuje besedo tako, da črke, ki jih igralec še ni uganil, zamenja s piko. Igralec vnese znak (pri čemer pazite na to, da lahko vnaša tudi male tiskane črke - spremenite jih v velike). Če beseda vsebuje vnešeni znak, se ti znaki v besedi "razkrijejo". Če beseda ne vsebuje želenega znaka, pa igralec "izgubi eno življenje". V začetku ima igralec 6 življenj; življenja se izpisujejo za besedo, med besedo in številom življenj mora biti en presledek. Igre je konec, ko igralec bodisi ugane vse črke, ki jih vsebuje beseda, bodisi izgubi vseh šest življenj. V prvem primeru mora računalnik izpisati "Bravo!" v drugem pa "Konec, iskana beseda je RESITEV.", kjer namesto RESITEV izpise besedo, ki smo jo (neuspešno) ugibali. Uspešna igra naj bo videti takole:
...... 6
a
.A.... 6
e
.A.... 5
i
.A.... 4
o
.A..O. 4
r
.A..O. 3
l
.A..O. 2
k
.A..O. 1
t
.A.TO. 1
s
.ASTO. 1
n
NASTO. 1
p
NASTOP 1
Bravo!
Neuspešna pa bo takšna.
....... 6
a
....... 5
b
....... 4
c
....... 3
d
D...D.. 3
e
D...DE. 3
f
D...DE. 2
g
D.G.DE. 2
h
D.G.DE. 1
i
Konec, iskana beseda je DOGODEK.
NALOGA NIMA TESTA
import random def igra(): kolikoJihJe = 8175 # smo pokukali ... beseda = vrniSamostalnik(random.randint(1, kolikoJihJe)) izbrane = set() zivljenj = 6 while zivljenj: print(pokaziZnake(beseda, izbrane), zivljenj) if imaVseZnake(beseda, izbrane): print("Bravo!") break crka = input().upper() if not kjeJeZnak(beseda, crka): zivljenj -= 1 izbrane.add(crka) if not zivljenj: print("Konec, iskana beseda je {}.".format(beseda))
Janko ne mara matematike, je pa navdušen programer. In ker je v šoli dobil cel kup matematičnih nalog iz množic, jih bo rajši rešil tako, da bo napisal ustrezne programe v Pythonu.
Sestavi funkcijo vrniTri(a, b)
, ki vrne nabor (A, B, C)
, kjer so A, B in C naslednje množice:
Pri tem vemo, da velja
def vrniTri(a, b): '''vrne nabor treh matematično opisanih množic''' A = set() for n in range(1, a): A.add(30*n) B = set() n = 1 while 5*n < b: B.add(n*n*n) n += 1 C = set() n = 1 while n*n*n < a*b: C.add(5*n) n += 1 return (A, B, C)
Sestavi funkcijo računi(A, B, C)
, ki vrne nabor (X, Y, Z)
, kjer so X
, Y
in Z
naslednje množice:
>>> računi({2, 4, 6, 8, 10}, {1, 2, 3, 4}, {4, 6, 5})
({4}, {8, 10}, {4, 5, 6, 8, 10})
def računi(A, B, C): '''Računamo z množicvami ...''' X = A & B & C Y = A - (B | C) Z = (A - B) | C return (X, Y, Z)
Sestavi funkcijo kartezični(A, B)
, ki vrne nabor (X, Y)
, kjer sta X
in Y
množici:
>>> kartezični({1, 2, 3}, {3, 4})
({(1,3), (1,4), (2,3), (2,4), (3,3), (3,4)}, {(3,3), (3,4), (4,3), (4,4)})
def kartezični(A, B): '''vrne nabor (X, Y), kjer X = A x B in Y = B x B''' X = set() for el1 in A: for el2 in B: X.add((el1, el2)) Y = set() for el1 in B: for el2 in B: Y.add((el1, el2)) return (X, Y)
Dane so množice
vrniD(a, b)
, ki vrne
>>> vrniD(20, 13)
{15,17,19}
def vrniD(a, b): '''A = {x, x € N & x < a) B = {x, x € N & x > b) C = {2a + 1, a € N} D = (A /\ B) - C' ''' D = set() # v preseku so naravna števila med b in a # zaradi - C' ohranimo le liha števila, razen 1! for x in range(b + 1, a): if x % 2 == 1: D.add(x) # znebimo morebitne 1 D.discard(1) # ne smemo uporabiti remove! return D
Mirko (saj veste kateri - tu je cel film o njem si ogleduje spisek vseh deklet, ki so mu všeč:
Ker sta s Slavkom tudi po vojni ostala "nerazdvojna druga", Mirko ne želi hoditi z nobeno od Slavkovih bivših deklet. Slavko mu je poslal spisek svojih bivših.
Pomagaj Mirku in sestavi funkcijo toBoMojeDekle(spisekKandidatk, spisekSlavkovih)
ki dobi dva seznama in vrne po abcedi urejen seznam deklet, med katerimi bo izbiral Mirko.
A šarmerja, kot sta, imata izjemno dolga spiska. Zato bo "enostavna" rešitev
for dekle in spisekKandidatk:
if dekle not in spisekSlavkovih:
kandidatke.append(dekle)
prepočasna. Sestavi torej metodo, kjer ne boš uporabil zanke (ne while in ne for, seveda pa tudi ne rekurzije)
>>> toBoMojeDekle(['Jožica', 'Marjetka', 'Anja', 'Petra', 'Marija'],
['Cilka', 'Petra', 'Pepca', 'Francka', 'Marija'])
['Anja', 'Jožica', 'Marjetka']
def toBoMojeDekle(sezKand, sezSlavko): '''Vrne seznam možnih deklet za Mirka. Dejansko vrne seznam elementov tistih iz sezKand, ki niso v sezSlavko ''' mnoMirko = set(sezKand) mnoSlavko = set(sezSlavko) katere = mnoMirko - mnoSlavko # razlika množic return sorted(katere) # želimo urejen seznam
Na http://bos.zrc-sazu.si/sbsj.html je 354.205 različnih besed iz gesel zbirke Besede slovenskega jezika. Program
import urllib.request
naslov = "http://bos.zrc-sazu.si/sbsj.html"
vir = urllib.request.urlopen(naslov)
vse = vir.read().decode()
besede = vse.split('\n')[15:]
poskuša iz te datoteke narediti seznam vseh besed. Ampak kot vidimo,
smo na začetku odrezali premalo. Prav tako se nismo znebili konca ...
Sestavi funkcijo vrniBesedo(n)
, ki vrne n-ti besedo iz te datoteke.
Pri tem naj se n obnaša kot indeks v seznamu!
>>> vrniBesedo(354204)
žžžžk
>>> vrniBesedo(354205)
Traceback (most recent call last):
...
IndexError: list index out of range
>>> vrniBesedo(0)
a
>>> vrniBesedo(-1)
žžžžk
def odst(niz): '''Iz niza odstrani <br>\r''' return niz[:-5] def vrniBesedo(n): '''Vrne n-to besedo. Rešitev predpostavlja, da se besede začno v 15. vrstici in nehajo 13 vrstic pred koncem. Taka struktura je bila konec l. 2015 Namenoma ni uporabljano iskanje prve (a) oz. zadnje besede ('žžžžk') ''' import urllib.request naslov = "http://bos.zrc-sazu.si/sbsj.html" vir = urllib.request.urlopen(naslov) vse = vir.read().decode() besede = vse.split('\n')[15:-13] slečene = list(map(odst, besede)) return slečene[n]
Sestavi funkcijo sameRazlične(zač)
, ki vrne množico vseh tistih slovenskih
besed, ki se začno z nizom zač
in jih sestavljajo same različne črke!
>>> sameRazlične('mate')
{'mate', 'maternik', 'materski', 'matec', 'matenski',
'matek', 'maten', 'matevž', 'maternski', 'mater', 'materin'}
def odst(niz): '''Iz niza odstrani <br>\r''' return niz[:-5] def vrniBesede(): '''Vrne vse besede is SSKJ. Rešitev predpostavlja, da se besede začno v 15. vrstici in nehajo 13 vrstic pred koncem. Taka struktura je bila konec l. 2015 Namenoma ni uporabljano iskanje prve (a) oz. zadnje besede ('žžžžk') ''' import urllib.request naslov = "http://bos.zrc-sazu.si/sbsj.html" vir = urllib.request.urlopen(naslov) vse = vir.read().decode() besede = vse.split('\n')[15:-13] slečene = list(map(odst, besede)) return slečene def enakeČrke(niz): '''Ali je niz sestavljen iz samih različnih črk''' return len(niz) == len(set(niz)) def sameRazlične(zač): '''Vrne množico tistih slovenskih besed, ki so sestavljene i z samih enakih črk in se začno z zač''' vseBesede = vrniBesede() mnBesed = set() for beseda in vseBesede: if beseda.startswith(zač) and enakeČrke(beseda): mnBesed.add(beseda) return(mnBesed)
Začetna vaje iz rekurzije
Imejmo poljubno celo število v seznamu v seznamu v seznamu ... v seznamu,
poljubno mnogokrat. Takšni strukturi bomo rekli babuška.
Primeri babušk so 13
, [473]
, [[[[21]]]]
, [[7]]
, itd.
Sestavi funkcijo babuska(par)
,
ki za parameter dobi takšno babuško ter vrne število seznamov, v katere je
zaprto celo število. Za zgornje primere so rezultati 0, 1, 4 in 2.
Predpostavi, da je struktura pravilna, torej res opisana kot zgoraj!
def babuska(mojaB): '''Vrne število seznamov, v katere je zaprto celo število ''' if isinstance(mojaB, int) : # ustavitveni pogoj - opraviti imamo s celim številom return 0 # imamo torej vsaj eno zunanjo lupino znotraj = mojaB[0] # odluščimo # in preštejemo koliko jih je znotraj koliko = babuska(znotraj) return 1 + koliko
Sestavi funkcijo kdoSeSkriva(par)
,
ki za parameter dobi takšno babuško ter vrne zaprto celo število.
Predpostavi, da je struktura pravilna, torej res opisana kot zgoraj!
Pri reševanju boste morali preveriti, kakšnega tipa je podatek. V
ta namen v ukazni lupini preizkusite naslednje ukaze:
isinstance(12, int)
x = 3.5
isinstance(x, float)
isinstance(x, int)
isinstance(x, (int, float))
isinstance(3, str)
isinstance("3", str)
isinstance([], list)
s = [2, [3]]
isinstance(s, list)
isinstance(s[0], list)
isinstance(s[0], int)
isinstance(s[1], int)
isinstance(s[1], list)
isinstance(s[1][0], int)
def kdoSeSkriva(mojaB): '''Vrne število seznamov, v katere je zaprto celo število ''' if isinstance(mojaB, int) : # število ni skrito! return mojaB # imamo torej vsaj eno zunanjo lupino znotraj = mojaB[0] # odluščimo # in poglejmo, kaj je znotraj kdo = kdoSeSkriva(znotraj) return kdo
Napišite rekurzivno funkcijo dolzina
, ki sprejme niz in izračuna njegovo dolžino.
Niz je sestavljen samo iz črk in števk. Dolžino izračunajte po takšnem pravilu:
vsaka števka k dolžini prispeva svojo vrednost, vsaka črka pa 1 (kot običajno).
Primeri:
>>> dolzina('5a')
6
>>> dolzina('abcde12345')
20
V funkciji ne smete uporabiti zanke while
ali zanke for
!
Pri ugotavljanju, ali gre za črko ali števko si pomagajte s funkcijama isalpha()
in isdigit()
.
Na primer:
>>> 'a'.isalpha()
True
>>> '5'.isdigit()
True
def dolzina(s): '''Izračun drugačne dolžine niza''' if s == "": return 0 # razbijemo na prvi znak in preostanek (rep) prviZnak = s[0] rep = s[1:] dolzinaRepa = dolzina(rep) # kako prištejemo prvi znak if prviZnak.isalpha(): return 1 + dolzinaRepa elif prviZnak.isdigit(): return int(prviZnak) + dolzinaRepa def dolzinaV2(niz): '''vrne "dolzino" niza, kjer je dolžina def. nekoliko drugače''' if niz == '': return 0 if len(niz) == 1 : # samo en znak v nizu if niz.isdigit() : # in to je števka return(int(niz)) return 1 # ni števka, je "navaden" znak # "dolzina" celega niza je "dolzina" niza, ki ga # sestavlja le prvi znak in "dolzine" preostanka return dolzina(niz[0]) + dolzina(niz[1:])
Seznam seznamov celih števil (SSCŠ) je seznam, katerega elementi so bodisi cela števila bodisi seznami seznamov celih števil. Da bo enostavneje, recimo, da je tudi prazen seznam SSCŠ. Nekaj primerov:
[-1, 2, -3]
[1, [2], 3, [2, 3, 4]]
[[[[2]], 1], [2, [[-3], [4]]]]
Sestavi funkcijo prestejStevila(sscs)
, ki prešteje, koliko je
v sscs celih števil. Za primere od zgoraj so rezultati:
3
6
5
def prestejStevila(sscs): if len(sscs) == 0 : # tudi prazen seznam je SSCS return 0 # in nima celih števil kolikoStevil = 0 # pregledamo vse elemente for el in sscs : # če je element 'običajno število' if isinstance(el, int): kolikoStevil += 1 else : # potem mora pa biti sscs in moramo prešteti vsa cela števila v njem kolikoVSSCS = prestejStevila(el) kolikoStevil += kolikoVSSCS return kolikoStevil
Sestavi funkcijo prestejNegativnaStevila(sscs)
, ki prešteje,
koliko je v seznamu seznamov negativnih celih števil.
Za primere od zgoraj so rezultati:
2
0
1
def prestejNegativnaStevila(sscs): if len(sscs) == 0 : # tudi prazen seznam je SSCS return 0 # in nima celih števil kolikoStevil = 0 # pregledamo vse elemente for el in sscs : # če je elemnt 'običajno število' if isinstance(el, int): if el < 0: # če je negativen, povečamo števec, drugače nič! kolikoStevil += 1 else : # potem mora pa biti sscs in moramo prešteti vsa neg. cela števila v njem kolikoVSSCS = prestejNegativnaStevila(el) kolikoStevil += kolikoVSSCS return kolikoStevil
Sestavi funkcijo sestejStevila(sscs)
, ki sešteje vsa cela števila
v seznamu seznamov celih števil. Za primere od zgoraj so rezultati:
-2
15
6
def sestejStevila(sscs): if len(sscs) == 0 : # tudi prazen seznam je SSCS return 0 # z vsoto 0 vsotaStevil = 0 # pregledamo vse elemente for el in sscs : # če je element 'običajno število' if isinstance(el, int): vsotaStevil += el # ga dodamo vsoti else : # če ni, pa mora biti sscs in njegovo vsoto dodamo skupni vsotaTegaEl = sestejStevila(el) vsotaStevil += vsotaTegaEl return vsotaStevil
Sestavi funkcijo jeSSCS(sscs)
, ki preveri
(vrne True oz. False), če je dan seznam res seznam seznamov celih števil.
def jeSSCS(sscs): if not isinstance(sscs, list): # če sploh ne gre za seznam return False if len(sscs) == 0 : # tudi prazen seznam je SSCS return True # pregledamo vse elemente for el in sscs : # če je element ni ne SSCS ne celo število if not isinstance(el, int) and \ not jeSSCS(el) : # ne SSCE return False # vsi testi OK return True
Sestavi funkcijo splosci(sscs)
, ki "splošči" seznam
seznamov celih števil, torej vrne navaden seznam celih števil,
ki so vsebovana v SSCŠ (v istem vrstnem redu). Za primere od zgoraj so rezultati:
[-1, 2, -3]
[1, 2, 3, 2, 3, 4]
[2, 1, 2, -3, 4]
def splosci(sscs): if len(sscs) == 0 : # prazen seznam je SSCS return [] # in vrnemo enakega noviSez = [] # pregledamo vse elemente for el in sscs : # če je element 'običajno število' if isinstance(el, int): noviSez.append(el) # ga dodamo seznamu else : # če ni, pa mora biti sscs in dodamo sploščeno različico splosceniDel = splosci(el) noviSez.extend(splosceniDel) return noviSez
Nekega dne je Ančka vsa obupana prosila brata Jureta, naj ji napiše program za domačo nalogo. Ta bi moral rekurzivno izračunati vsoto prvih n naravnih števil. A ker se je Juretu mudilo na vsakodnevni žur, je moral zelo hiteti in je zato v programu naredil nekaj napak. Jih najdeš?
def vsota( n) :
if n > 0 :
return 1
else :
return vsota(n-1)
def vsota( n) : if n <= 0 : return 0 else : return n + vsota(n-1)
Jure je napisal kodo, ki s pomočjo rekurzije izračuna
vsoto 1 + 1/2 + 1/3 + ... + 1/n
. Žal mu je med sprehodom
list s kodo padel v sneg in se je nekaj kode izbrisalo. Dopolni jo!
def vsotaRec(n) :
'''Izračun 1 + 1/2 + ... + 1 / n
n je zagotovo naravno število
'''
if _______________ : # ustavitveni pogoj
return ___________
return ___________ + vsotaRec(_______) # rekurzivni klic
def vsotaRec(n) : '''Izračun 1 + 1/2 + ... + 1 / n n je zagotovo naravno število ''' if n == 1 : # ustavitveni pogoj return 1 return 1 / n + vsotaRec(n - 1) # rekurzivni klic
Dana je rekurzivna funkcija `izpisObratniR', ki izpiše števila v obratnem vrstnem redu.
def izpisObratniR(stevec) :
if stevec <= 0 :
return ""
else :
niz = "" + str(stevec) + ", " + izpisObratniR(stevec - 1)
return niz
Kot vidiš, se na koncu izpiše odvečna vejica. Potrebujemo metodo, ki bi še vedno uporabljala rekurzijo, a ne bi izpisala dodatne vejice
def izpisObratniR(stevec): '''Znebimo se odvečne , ''' if stevec <= 0: return "" if stevec == 1: return "1" niz = "" + str(stevec) + ", " + izpisObratniR(stevec - 1) return niz
Sedaj na osnovi te metode sestavi izpisR(stevec)
, ki bo vrnila števila v
"pravem" vrstnem redu. Še vedno pa uporabi rekurzijo in pazi, da
ne bo odvečnih vejic!
def izpisR(stevec): if stevec <= 0 : return "" if stevec == 1 : return "1" niz = izpisR(stevec - 1) + ', ' + str(stevec) return niz
Sestavite rekurzivno funkcijo steviloEnk(n)
, ki prešteje, koliko je
enk v dvojiškem zapisu nenegativnega celega števila n
.
Primer: Število 52 je v dvojiškem zapisu enako 110100, torej so v njem tri enke. Če se ne spomniš postopka, si oglej ta posnetek
def steviloEnk(n): '''Koliko enk je v dvojiškem zapisu števila n''' if n < 2: return n return n % 2 + steviloEnk(n // 2)
Janezek mora za kazen prebarvati vrtno ograjo. Ta je sestavljena iz deščic širine 1 dm, ki so položene tesno skupaj ena ob drugi. Deščice so različnih višin, saj je ograjo izdelal Janezek sam iz odvečnih kosov, vsaka deščica pa se dotika tal, ki so ravna. Ograja izgleda nekako takole:
+-+
+-+ | | +-+
| | +-+-+ | | |
+-+ | | | | +-+-+ +-+
| | +-+ | | | | | | |
| | | | | | | | | | |
---------------------------
Janezek pozna višino vsake deščice, zato lahko ograjo opiše s seznamom, ki za vsako deščico vsebuje po eno število (višina v dm):
[2, 4, 1, 3, 3, 5, 2, 2, 4, 2]
Janezek ima čopič, ki je širok ravno 1 dm. Ograjo bo barval z navpičnimi in vodoravnimi potegi čopiča (nikoli ne vleče čopiča diagonalno). To počne tako, da se ob vsakem trenutku vse ščetine čopiča dotikajo ograje. Ponovno lahko potegne čopič tudi preko že pobarvanega dela ograje.
Janezek bi rad prebarval ograjo z minimalnim številom potez, da bi
lahko čimprej odšel na obisk k Pepci. Sestavite funkcijo
stevilo_potez(ograja)
, ki dobi seznam z opisom ograje in vrne
minimalno število potez. Zgled:
>>> stevilo_potez([2, 2, 1, 2, 1])
3
>>> stevilo_potez([2, 2])
2
>>> stevilo_potez([5])
1
def stevilo_potez(ograja): '''Koliko potez je potrebnih za prebarvanje ograje ''' if len(ograja) == 0: # ni ograje return 0 if len(ograja) == 1: # eno deščico prebarvamo naenkrat return 1 min_visina = min(ograja) poteze = min_visina # Vodoravne poteze. # sedaj barvamno od leve proti desni p = [] # kaj je ostalo še za prebarvati na levi strani for i in range(len(ograja)): # pogledamo vse deščice if ograja[i] != min_visina: # deščica je višja, kot najnižja p.append(ograja[i] - min_visina) # pobarvati moramo še njen zgornji del else: # pobarvati moram vse levo, kar še nismo pobarvali prej poteze += stevilo_potez(p) # Barvanje "podograje". p = [] # levo je sedaj pobarvano vse poteze += stevilo_potez(p) # ko smo na koncu, pobarvamo še preostale višje dele return min(poteze, len(ograja)) # Druga možnost so same navpične poteze.
Pri črkovalnikih (npr. Besana), optičnem prepoznavanju znakov in še marsikje nam zelo prav pride, če znamo za dva niza ugotoviti, kako podobna sta si, oziroma kakšna je razdalja med njima. Poznamo več različnih razdalj med nizi: Hammingovo, Damerau-Levenshteinovo, razdaljo največjega skupnega podniza ...
V MaFiRa Wikiju piše, da
Levenshteinova razdalja (angl. Levenshtein distance ali edit distance) med
dvema nizoma predstavlja minimalno število operacij, ki jih potrebujemo za
preoblikovanje enega niza v drugega. Operacije so izbris, vstavljanje in
zamenjava znakov. Dolžini nizov sta lahko poljubni.
Niz
Npr. 'banana' se od 'ananas' razlikuje za 2, ker potrebujemo vsaj dve operaciji, da iz banane naredimo ananas. Npr.
'banana' --(zbrišemo b)-> 'anana' --(vstavimo s)-> 'ananas'
Verjetno se ne boste čudili, da je razdalja med pojmoma 'matematika' in 'fizika' kar 7 ;-)
Sestavite funkcijo levenshteinovaRazdalja(a, b)
, ki kot argumenta prejme
niza a
in b
. Funkcija naj vrne urejevalniško razdaljo med a
in b
.
>>> levenshteinovaRazdalja('banana', 'ananas')
2
>>> levenshteinovaRazdalja('potop', 'pokol')
2
>>> levenshteinovaRazdalja('matematika', 'fizika')
7
Nalogo rešite z rekurzijo, torej brez uporabe zanke for
oziroma while
.
Namig: niza si predstavljajte kot xA
in yB
. In potem preverite, katera od treh
možnost za predelavo bo dala minimalno vrednost ... Pri tem ne pozabite še na možnost, da
je x == y
def levenshteinovaRazdalja(a, b): ''' Vrne Levenshteinovo razdaljo med nizoma a in b''' if a == "": # v prazen niz moramo vstaviti vse znake iz b return len(b) if b == "": # pobrisati moramo vse znake iz a return len(a) if a[0] == b[0]: # če bomo znak pustili in spreminjali preostanek dodatek = 0 else: dodatek = 1 # tu bomo znaka zamenjali # lahko znak iz a pobrišemo in preostanek a spremenimo v b # ali a spremenimo v cel b razen prvega in na začetek vstavimo prvi znak b-ja # ali pa preostanek a spremenimo v preostanek b in upoštevamo še morebitno spremembo prvega znaka return min(1 + levenshteinovaRazdalja(a[1:], b), levenshteinovaRazdalja(a, b[1:]) + 1, dodatek + levenshteinovaRazdalja(a[1:], b[1:]))
Oznake idej se nanašajo na prosojnice permutacije v spletni učilnici FMF za predmet Programiranje 1 v š.l. 15/16
Če hočemo narediti permutacijo iz 0 elementov, vrnemo tako kot itertools [[]]
Na osnovi ideje 1 smo zgradili osnutek metode permutacijeV1(seznam)
.
Dopolni ga do delujočega!
def permutacijeV1(seznam):
'''Vrne seznam seznamov, kjer posamezni seznam predstavlja
permutacijo elementov iz seznama '''
... manjka
prviDel = seznam[:-1]
zadnji = seznam[-1]
permPrej = permutacijeV1(prviDel)
# vstavi zadnji na vsa možna mesta
rez = []
for
koncnaPer = permPrej z vstavljenim zadnjim
rez.append(koncnaPer)
...
return sorted(rez)
def permutacijeV1(seznam): '''Vrne seznam seznamov, kjer posamezni seznam predstavlj permutacijo elementov iz seznama ''' if seznam == []: # ni elementov, le prazna permutacija return [[]] if len(seznam) == 1: # en sam element - ena permutacija! return [[seznam[0]]] prviDel = seznam[:-1] zadnji = seznam[-1] permPrej = permutacijeV1(prviDel) rez = [] for posameznaP in permPrej: '''Iz te perm. naredimo len(seznam) novih ''' for i in range(len(seznam)): novaP = posameznaP[:] novaP.insert(i, zadnji) rez.append(novaP) return sorted(rez)
Na osnovi ideje 2 smo zgradili osnutek metode permutacijeV2(seznam)
.
Dopolni ga do delujočega!
def permutacijeV2(seznam):
'''Vrne seznam seznamov, kjer posamezni seznam predstavlja
permutacijo elementov iz seznama '''
... manjka
vse = []
for ind, elt in enumerate(seznam):
# zgradimo vse permutacije iz ostalih
vsePerm = permutacijeV2(seznam[:ind] + seznam[ind + 1:] )
# in sedaj permutacijam dodamo na začetek element elt
...
...
return sorted(vse)
def permutacijeV2(seznam): '''Vrne seznam seznamov, kjer posamezni seznam predstavlja permutacijo elementov iz seznama ''' if seznam == []: # ni elementov, le prazna permutacija return [[]] vse = [] for ind, elt in enumerate(seznam): # zgradimo vse permutacije iz ostalih vsePerm = permutacijeV2(seznam[:ind] + seznam[ind + 1:] ) # in sedaj permutacijam dodamo na začetek element elt for perm in vsePerm: vse.append([elt] + perm) return sorted(vse)
Na osnovi ideje 3 smo zgradili osnutek metode permutacijeV3(seznam)
.
Dopolni ga do delujočega!
def permutacijeV3(seznam, doSedaj = []):
'''Vrne seznam vseh možnih permutacij iz elementov v elementi,
ki imajo začetek enak permutaciji, ki so predstava doSedaj'''
# Če smo že na koncu
return [doSedaj]
vse = []
for elt in seznam:
# če elt še lahko dodamo v doslej sestavljeno permutacijo
# generiramo vse permutacije z začetkom doSedaj + [elt]
# dodamo vsem
return sorted(vse)
def permutacijeV3(seznam, doSedaj = []): '''Vrne seznam vseh možnih permutacij iz elementov v elementi, ki imajo začetek enak permutaciji, ki so predstava doSedaj''' if seznam == []: # ni elementov, le prazna permutacija return [[]] if len(seznam) == len(doSedaj):# Če smo že na koncu return [doSedaj] vse = [] for elt in seznam: if not elt in doSedaj: # če elt še lahko dodamo v doslej sestavljeno permutacijo permut = permutacijeV3(seznam, doSedaj + [elt]) # generiramo vse permutacije z začetkom doSedaj + [elt] vse += permut #dodamo vsem return sorted(vse)
Na osnovi ideje 4 smo zgradili osnutek metode permutacijeV4(seznam)
.
Dopolni ga do delujočega!
import itertools
def permutacijeV4(seznam):
'''Vrne seznam seznamov, kjer posamezni seznam predstavlja
permutacijo elementov iz seznama '''
# uporabimo itertools
# pazimo, ker ta vrne seznam naborov!
return sorted(vse)
import itertools def permutacijeV4(seznam): '''Vrne seznam seznamov, kjer posamezni seznam predstavlja permutacijo elementov iz seznama ''' # uporabimo itertools permu = itertools.permutations(seznam) vse = list(map(list, permu)) # pazimo, ker ta vrne seznam naborov! return sorted(vse)
Sklop nalog, kjer pišemo funcije, ki naredijo določena opravila z datotekami na nivoju operacijskega sistema. V nalogah bodo potrebne te funkcije:
os.listdir(mapa)
seznam datotek in map v mapios.path.isfile(dat)
ali je dat »navadna« datotekaos.path.isdir(dat)
ali je dat imenikos.path.getsize(dat)
velikost datotekeos.path.split(dat)
razdeli ime datotekeos.path.getmtime(dat)
čas zadnje spremembe datotekeos.rmdir(pot)
odstrani mapo Za preverjanje nalog v imenik/mapo, kjer imate rešitve, skopirajte to
datoteko ZIP
in jo razširite (nastala bo mapa PythonOsRek
s podmapami testX
in EURO2012
)
Sestavi funkcijo vrniMape_IskDat(potDoMape,imeDatoteke)
,
ki vrne po abecedi urejen seznam vseh map, ki vsebujejo dano datoteko.
Pri tem pot začni opisovati šele pri mapi potDoMape
izpisiMape_IskDat('.\\PythonOSRek\\test1', 'drevo.py')
['.\\PythonOSRek\\test1', '.\\PythonOSRek\\test1\\PodM\\TraRa']
če potDoMape ne opisuje datoteke, vrni None
import os def vrniMape_IskDat(potDoMape,imeDatoteke): '''vrne po abecedi urejen seznam vseh map, ki vsebujejo dano datoteko.''' if not os.path.isdir(potDoMape): # ni te mape return None seznamMap_IskDat = [] #shranimo poti do iskane datoteke if imeDatoteke in os.listdir(potDoMape): # pogledamo datoteke "na vrhu" seznamMap_IskDat.append(potDoMape) for datoteka in os.listdir(potDoMape): ime = potDoMape + "\\" + datoteka if os.path.isdir(ime): # gre za mapo vPodmapi = vrniMape_IskDat(ime,imeDatoteke) seznamMap_IskDat.extend(vPodmapi) return sorted(seznamMap_IskDat)
Sestavi funkcijo najvecDatVMapi(potDoMape)
, ki v izbrani mapi (in njenih podmapah)
poišče mapo, ki vsebuje največ datotek (ne podmap). Funkcija naj vrne ime iskane mape (skupaj s potjo)
ter število datotek v tej mapi. Če je takih map več, vrni prvo po abecedi (upoštevaj polno
ime, skupaj s potjo!)
import os def najvecDatVMapi(mapa): ''' Funkcija vrne ime iskane mape (skupaj s potjo) ter število datotek v tej mapi. Če je takih map več, vrne prvo po abecedi (upošteva polno ime, skupaj s potjo!)''' najvecjaIme = mapa #prestejemo datoteke v tej mapi steviloDatotek = 0 for trenDat in os.listdir(mapa): if os.path.isfile(mapa + "\\" + trenDat): steviloDatotek +=1 najvecjaVelikost = steviloDatotek #mapo z najvec datotek primerjamo z naj mapami v podmapah seznamMap = [] # naredimo seznam podmap for trenMapa in os.listdir(mapa): if os.path.isdir(mapa + "\\" + trenMapa): seznamMap.append(trenMapa) #rekruzivno pregledamo podmape for mape in seznamMap: najvecjaImeImenik, najvecjaVelikostImenik = najvecDatVMapi(mapa + "\\" + mape) #če ima trenutna mapa enako prejsna ni potrebno narediti nič, ker so že po abecedi! if najvecjaVelikostImenik > najvecjaVelikost: najvecjaVelikost = najvecjaVelikostImenik najvecjaIme = najvecjaImeImenik return najvecjaIme, najvecjaVelikost
Sestavi funkcijo prestejDatoteke(potDoMape)
,
ki prešteje, koliko je vseh datotek v izbrani mapi.
Pri tem naj šteje tudi datoteke v podmapah, map pa naj ne šteje.
Če potDomape ne opisuje mape, vrni None
import os def prestejDatoteke(potDoMape): ''' Vrne stevilo datotek v mapi in njenih podmapah.''' if not os.path.isdir(potDoMape): # ni te mape return None steviloDatotek = 0 #prestejemo datoteke for trenDat in os.listdir(potDoMape): if os.path.isfile(potDoMape + "\\" + trenDat): steviloDatotek += 1 else: # gre za mapo steviloDatotek += prestejDatoteke(potDoMape + "\\" + trenDat) return steviloDatotek
Sestavi funkcijo vrniDatPy(potDoMape)
, ki vrne po abecedi
urejen seznam (polnih)imen vseh
datotek v izbrani mapi in njenih podmapah, ki imajo končnico .py.
import os def vrniDatPy(potDoMape): '''Izpise imena vseh datotek (skupaj s potjo), ki imajo koncnico .py.''' if not os.path.isdir(potDoMape): # ni te mape return None seznamMap_IskDat = [] #shranimo poti do iskane datoteke for datoteka in os.listdir(potDoMape): # pogledamo vse datoteke in datoteke v imenikih ime = potDoMape + "\\" + datoteka if os.path.isfile(ime): # gre za navadno datoteko končnica = os.path.splitext(datoteka)[1] if končnica == '.py': seznamMap_IskDat.append(ime) elif os.path.isdir(ime): # gre za mapo vPodmapi = vrniDatPy(ime) seznamMap_IskDat.extend(vPodmapi) return sorted(seznamMap_IskDat)
Sestavi funkcijo izbrisiPrazneMape(potDoMape)
,
ki v izbrani mapi (in njenih podmapah) pobriše vse prazne datoteke
(tiste z velikostjo 0) in vse prazne mape (tiste, ki ne vsebujejo nobenih datotek ali podmap).
Funkcija naj vrne par, ki ga sestavljata število pobrisanih datotek in število pobrisanih map,
oziroma None
, če potDoMape ne opisuje imenika
Pozor: ko zbrišemo prazno datoteko, se lahko sprazni tudi mapa.
Pred testiranjem vedno skopirajte to
datoteko ZIP
(staro mapo PythonOsRek
pobrišite!)
in jo razširite (nastala bo mapa PythonOsRek
s podmapami testX
in EURO2012
)
import os def izbrisiPrazneMape(potDoMape): '''Izbriši vse prazne datoteke in prazne mape''' kolikoDat, kolikoMap = 0, 0 if not os.path.isdir(potDoMape): # ni mapa return None vseDat = os.listdir(potDoMape) for datoteka in vseDat: #izbrisemo samo prazne datoteke if os.path.isfile(potDoMape + "\\" + datoteka) and os.path.getsize(potDoMape + "\\" + datoteka) == 0: os.remove(potDoMape + "\\" + datoteka) kolikoDat += 1 elif os.path.isdir(potDoMape + "\\" + datoteka): #filtriramo mape kolDat, kolMap = izbrisiPrazneMape(potDoMape + "\\" + datoteka) kolikoDat += kolDat kolikoMap += kolMap #če je mapa sedaj prazna, jo izbrisemo if len(os.listdir(potDoMape)) == 0: os.rmdir(potDoMape) kolikoMap += 1 return kolikoDat, kolikoMap
Naloga nima testnega programa! V Tomu so le zato, da so "na kupu"
Vsaka oddaja bo označena kot pravilna!
Izpiši mapo
Sestavi funkcijo izpisiDat_izbMapa(potDoMape)
, ki izpiše vse datoteke
v izbrani mapi in njenih podmapah.
Funkcija naj izpisuje samo imena datotek, brez poti.
Uporabi izpis z zamikanjem, da bo razvidno, kateri mapi pripada
katera datoteka. Vedno najprej izpiši datoteke, potem mape
a.txt
tra.py
bla
dat.txt
ble
blu
c.dat
xxx
yyy
e.dat
Sestavi funkcijo izpisiDatPy(potDoMape)
, ki izpiše imena vseh
datotek v izbrani mapi in njenih podmapah, ki imajo končnico .py.
Izpisuje naj polna imena (skupaj s potjo).
Naloge nimajo testnega programa! V Tomu so le zato, da so "na kupu". Vsaka oddaja bo označena kot pravilna!
Če uporabite datotečni strukturo iz datoteke ZIP, kot je opisana pri nalogi Pregled map in datotek, naj se vaše funkcije obnašajo kot kažejo zgledi!
Sestavi funkcijo izpisiDatVelikost(potDoMape, velikost)
,
ki vrne seznam polnih imen datotek v dani mapi in njenih podmapah,
katerih velikost je večja ali enaka dani vrednosti.
Sestavi funkcijo izpisiMape_IskDat(potDoMape,imeDatoteke)
, ki
izpiše vse mape, ki vsebujejo dano datoteko.
>>> izpisiMape_IskDat('.\\PythonOSrek', 'drevo.py')
.\PythonOSrek\test1\drevo.py
.\PythonOSrek\test1\podM\TraRa\drevo.py
.\PythonOSrek\test1a\drevo.py
.\PythonOSrek\test1a\podM\TraRa\drevo.py
>>>
Sestavi funkcijo najvecDatVMapi(potDoMape)
, ki v izbrani mapi (in njenih podmapah)
poišče mapo, ki vsebuje največ datotek (štejemo samo datoteke v mapi, ne tudi v podmapah, saj je
drugače naloga nesmiselna). Funkcija naj vrne ime iskane mape (skupaj s potjo)
ter število datotek v tej mapi.
>>> najvecDatVMapi('.\\PythonOSrek')
('.\\PythonOSrek\\test1', 7)
>>>
Poišči najnovejšo datoteko
Sestavi funkcijo poisciSezZadSprmDat(potDoMape)
, ki v izbrani mapi
(in njenih podmapah) poišče datoteke, ki so bile zadnje spremenjene.
Funkcija naj vrne seznam imen teh datotek (skupaj s potjo).
>>> poisciSezZadSprmDat('.\\PythonOSrek')
['.\\PythonOSrek\\EURO2012\\euro database.py']
>>>
Poišči najnovejšo datoteko
Sestavi funkcijo poisciZadSprmDat(potDoMape)
, ki v izbrani mapi
(in njenih podmapah) poišče datoteko, ki so bile zadnja spremenjena.
Funkcija naj vrne po abecedi najmanjše ime izmed teh datotek (skupaj s potjo).
>>> poisciZadSprmDat('.\\PythonOSrek')
'.\\PythonOSrek\\EURO2012\\euro database.py'
>>>
Poišči največjo datoteko
Sestavi funkcijo najvecjaDat(potDoMape)
, ki v izbrani mapi
(in njenih podmapah) poišče največjo datoteko. Funkcija naj vrne
par, ki ga sestavljata po abecedi zandje ime take datoteke (skupaj s potjo) in velikost
>>> najvecjaDat('.\\PythonOSrek')
('.\\PythonOSrek\\test1\\Tips.PNG', 94535)
>>>
Že pri prejšnjih nalogah smo spoznali SSČS. Ponovimo še enkrat - seznam seznamov celih števil (SSCŠ) je seznam, katerega elementi so bodisi cela števila bodisi seznami seznamov celih števil. Da bo enostavneje, recimo, da je tudi prazen seznam SSCŠ. Nekaj primerov:
[-1, 2, -3]
[1, [2], 3, [2, 3, 4]]
[[[[0]], 1], [2, [[-3], [4]]]]
Sestavi funkcijo ločiStevila(sscs)
, ki vrne trojico (poz, nic, neg)
, ki pove
koliko je v sscs pozitivnih, ničelnih in koliko negativnih celih števil. Za primere od zgoraj so rezultati:
(1, 0, 2)
(6, 0, 0)
(3, 1, 1)
Predpostavi, da je parameter zagotovo SSCS,
def ločiStevila(sscs): '''Razdeli podatke v SSCS na pozitivne, ničelne in negativne''' if len(sscs) == 0 : # tudi prazen seznam je SSCS return (0, 0, 0) # in nima celih števil kolikoPozStevil = 0 kolikoNegStevil = 0 kolikoNic = 0 # pregledamo vse elemente for el in sscs : # če je element 'običajno število' if isinstance(el, int): if el > 0: kolikoPozStevil += 1 elif el < 0: kolikoNegStevil += 1 else: kolikoNic += 1 else : # potem mora pa biti sscs in moramo prešteti vsa cela števila v njem trojka = ločiStevila(el) kolikoPozStevil, kolikoNic, kolikoNegStevil = kolikoPozStevil + trojka[0], \ kolikoNic + trojka[1], kolikoNegStevil + trojka[2] return kolikoPozStevil, kolikoNic, kolikoNegStevil
Sestavi funkcijo jeSSCS(sscs)
, ki preveri
(vrne True oz. False), če je dan seznam res seznam seznamov celih števil.
POZOR: Python pravi, da je isinstance(True, int)
enako True
, pa tudi
isinstance(False, int)
enako True
, zato se "znebi" napačnih logičnih
vrednosti z isinstance(True, bool)
def jeSSCS(sscs): '''Ali je sscs res seznam seznamov celih števil''' if not isinstance(sscs, list): # če sploh ne gre za seznam return False if len(sscs) == 0 : # tudi prazen seznam je SSCS return True # pregledamo vse elemente for el in sscs : # če je element logična vrednost if isinstance(el, bool): return False # če element ni ne SSCS ne celo število if not isinstance(el, int) and \ not jeSSCS(el) : # ne SSCE return False # vsi testi OK return True
Sestavi funkcijo kolikoNapacnih(sscs)
, ki prešteje,
koliko je v seznamu seznamov celih števil napačnih podatkov, torej elementov, ki
niso ne cela števila, ne SSCŠ. Če argument ni seznam, vrni None
>>>kolikoNapacnih([1, 'bla', 2])
1
>>>kolikoNapacnih([1, [['bla', 'blu'], False], 2])
1
>>>kolikoNapacnih([[1.8], [2, 3, [4]], [False, 4, [True]]])
2
>>>kolikoNapacnih(12)
None
def kolikoNapacnih(sscs): '''Koliko elementov je v sscs napačnih''' if not isinstance(sscs, list): return None kolikoNarobe = 0 # pregledamo vse elemente for el in sscs: if (not isinstance(el, int)) and (not jeSSCS(el)) \ or isinstance(el, bool): kolikoNarobe += 1 return kolikoNarobe
Oznake idej se nanašajo na prosojnice permutacije v spletni učilnici FMF za predmet Programiranje 1 v š.l. 15/16
Če hočemo narediti permutacijo iz 0 elementov, vrnemo tako kot itertools [[]]
Na osnovi ideje 1 smo zgradili osnutek metode permutacijeV1(seznam)
.
Dopolni ga do delujočega!
def permutacijeV1(seznam):
'''Vrne seznam seznamov, kjer posamezni seznam predstavlja
permutacijo elementov iz seznama '''
... manjka
prviDel = seznam[:-1]
zadnji = seznam[-1]
permPrej = permutacijeV1(prviDel)
# vstavi zadnji na vsa možna mesta
rez = []
for
koncnaPer = permPrej z vstavljenim zadnjim
rez.append(koncnaPer)
...
return sorted(rez)
def permutacijeV1(seznam): '''Vrne seznam seznamov, kjer posamezni seznam predstavlj permutacijo elementov iz seznama ''' if seznam == []: # ni elementov, le prazna permutacija return [[]] if len(seznam) == 1: # en sam element - ena permutacija! return [[seznam[0]]] prviDel = seznam[:-1] zadnji = seznam[-1] permPrej = permutacijeV1(prviDel) rez = [] for posameznaP in permPrej: '''Iz te perm. naredimo len(seznam) novih ''' for i in range(len(seznam)): novaP = posameznaP[:] novaP.insert(i, zadnji) rez.append(novaP) return sorted(rez)
Na osnovi ideje 2 smo zgradili osnutek metode permutacijeV2(seznam)
.
Dopolni ga do delujočega!
def permutacijeV2(seznam):
'''Vrne seznam seznamov, kjer posamezni seznam predstavlja
permutacijo elementov iz seznama '''
... manjka
vse = []
for ind, elt in enumerate(seznam):
# zgradimo vse permutacije iz ostalih
vsePerm = permutacijeV2(seznam[:ind] + seznam[ind + 1:] )
# in sedaj permutacijam dodamo na začetek element elt
...
...
return sorted(vse)
def permutacijeV2(seznam): '''Vrne seznam seznamov, kjer posamezni seznam predstavlja permutacijo elementov iz seznama ''' if seznam == []: # ni elementov, le prazna permutacija return [[]] vse = [] for ind, elt in enumerate(seznam): # zgradimo vse permutacije iz ostalih vsePerm = permutacijeV2(seznam[:ind] + seznam[ind + 1:] ) # in sedaj permutacijam dodamo na začetek element elt for perm in vsePerm: vse.append([elt] + perm) return sorted(vse)
Na osnovi ideje 3 smo zgradili osnutek metode permutacijeV3(seznam)
.
Dopolni ga do delujočega!
def permutacijeV3(seznam, doSedaj = []):
'''Vrne seznam vseh možnih permutacij iz elementov v elementi,
ki imajo začetek enak permutaciji, ki so predstava doSedaj'''
# Če smo že na koncu
return [doSedaj]
vse = []
for elt in seznam:
# če elt še lahko dodamo v doslej sestavljeno permutacijo
# generiramo vse permutacije z začetkom doSedaj + [elt]
# dodamo vsem
return sorted(vse)
def permutacijeV3(seznam, doSedaj = []): '''Vrne seznam vseh možnih permutacij iz elementov v elementi, ki imajo začetek enak permutaciji, ki so predstava doSedaj''' if seznam == []: # ni elementov, le prazna permutacija return [[]] if len(seznam) == len(doSedaj):# Če smo že na koncu return [doSedaj] vse = [] for elt in seznam: if not elt in doSedaj: # če elt še lahko dodamo v doslej sestavljeno permutacijo permut = permutacijeV3(seznam, doSedaj + [elt]) # generiramo vse permutacije z začetkom doSedaj + [elt] vse += permut #dodamo vsem return sorted(vse)
Na osnovi ideje 4 smo zgradili osnutek metode permutacijeV4(seznam)
.
Dopolni ga do delujočega!
import itertools
def permutacijeV4(seznam):
'''Vrne seznam seznamov, kjer posamezni seznam predstavlja
permutacijo elementov iz seznama '''
# uporabimo itertools
# pazimo, ker ta vrne seznam naborov!
return sorted(vse)
import itertools def permutacijeV4(seznam): '''Vrne seznam seznamov, kjer posamezni seznam predstavlja permutacijo elementov iz seznama ''' # uporabimo itertools permu = itertools.permutations(seznam) vse = list(map(list, permu)) # pazimo, ker ta vrne seznam naborov! return sorted(vse)
Sestavi funkcijo izbrisiPrazneMape(potDoMape)
,
ki v izbrani mapi (in njenih podmapah) pobriše vse prazne datoteke
(tiste z velikostjo 0) in vse prazne mape (tiste, ki ne vsebujejo nobenih datotek ali podmap).
Funkcija naj vrne par, ki ga sestavljata število pobrisanih datotek in število pobrisanih map,
oziroma None
, če potDoMape ne opisuje imenika
Pozor: ko zbrišemo prazno datoteko, se lahko sprazni tudi mapa.
Pred testiranjem vedno skopirajte to
datoteko ZIP
(staro mapo PythonOsRek
pobrišite!)
in jo razširite (nastala bo mapa PythonOsRek
s podmapami testX
in EURO2012
)
import os def izbrisiPrazneMape(potDoMape): '''Izbriši vse prazne datoteke in prazne mape''' kolikoDat, kolikoMap = 0, 0 if not os.path.isdir(potDoMape): # ni mapa return None vseDat = os.listdir(potDoMape) for datoteka in vseDat: #izbrisemo samo prazne datoteke if os.path.isfile(potDoMape + "\\" + datoteka) and os.path.getsize(potDoMape + "\\" + datoteka) == 0: os.remove(potDoMape + "\\" + datoteka) kolikoDat += 1 elif os.path.isdir(potDoMape + "\\" + datoteka): #filtriramo mape kolDat, kolMap = izbrisiPrazneMape(potDoMape + "\\" + datoteka) kolikoDat += kolDat kolikoMap += kolMap #če je mapa sedaj prazna, jo izbrisemo if len(os.listdir(potDoMape)) == 0: os.rmdir(potDoMape) kolikoMap += 1 return kolikoDat, kolikoMap
Collatzovo zaporedje tvorimo na sledeč način. Začnemo z nekim naravnim
številom
Vse naloge, razen prve, rešite z rekurzijo!
Sestavite funkcijo naslednji_clen(n)
, ki izračuna člen, ki v Collatzovemu
zaporedju sledi številu n
.
def naslednji_clen(n): '''člen, ki v Collatzovemu zaporedju sledi številu `n`''' if n % 2 == 0: return n // 2 else: return 3 * n + 1
Sestavite funkcijo dolzina_zaporedja(n)
, ki izračuna dolžino Collatzovega
zaporedja, ki se začne s številom n
.
def dolzina_zaporedja(n): '''dolžina Collatzovega zaporedja, ki se začne s številom `n`.''' if n == 1: return 1 else: return 1 + dolzina_zaporedja(naslednji_clen(n))
Sestavite funkcijo najvecji_clen(n)
, ki izračuna največji člen v
Collatzovem zaporedju, ki se začne s številom n
.
def najvecji_clen(n): '''največji člen v Collatzovem zaporedju, ki se začne s številom `n`.''' if n == 1: return 1 else: return max(n, najvecji_clen(naslednji_clen(n)))
Sestavite funkcijo najdaljse_zaporedje(m, n)
, ki vrne dolžino najdaljšega
zaporedja med vsemi tistimi Collatzovimi zaporedji, ki se začnejo s števili
med (vključno) m
in n
.
def najdaljse_zaporedje(m, n): '''Dolžina najdaljšega zaporedja med vsemi tistimi Collatzovimi zaporedji, ki se začnejo s števili med (vključno) m in n.''' if m == n: return dolzina_zaporedja(m) else: return max(dolzina_zaporedja(m), najdaljse_zaporedje(m + 1, n))
Dan je slovar, ki hrani podatke o tem, kakšen tovor smo naložili na tovornjak in kolikšna je bila masa posameznih kosov tovora. Na primer, slovar
{'televizor' : 17, 'zaboj piva' : 12, 'zofa' : 35}
pove, da smo na tovornjak naložili 17kg težak televizor, 12kg težak zaboj piva in 35kg težko zofo.
Sestavi funkcijo tezaTovora(tovor)
, ki sprejme tak slovar in vrne skupno težo tovora
(v našem primeru 17 + 12 + 35 = 64 kg).
def tezaTovora(tovor): ''' koliko je skupna teža tovora, podanega v slovarju tovor ''' skupaj = 0 for teza in tovor.values(): skupaj += teza return skupaj
Sestavi funkcijo lahkoPelje(tovor, nosilnost)
, ki ugotovi, ali tovornjak
z nosilnostjo nosilnost
lahko pelje tovor, dan s slovarjem tovor
def lahkoPelje(tovor, nosilnost): ''' ali tovornjak z nosilnostjo nosilnost lahko pelje tovor, dan s slovarjem tovor ''' return tezaTovora(tovor) <= nosilnost def lahkoPelje_V2(tovor, nosilnost): ''' koliko je skupna teža tovora, podanega v slovarju tovor Predpostavimo, da funkcije tezaTovora nimamo ''' # izračunajmo težo tovora skupaj = 0 for teza in tovor.values(): skupaj += teza # in preverimo, če gre return skupaj <= nosilnost
Sestavi funkcijo enakaTovora(tovor1, tovor2)
, ki ugotovi, če sta
tovora, podana v slovarjih tovor1
in tovor2
enaka! Tovora sta enaka, če vsebujeta
iste predmete z isto težo
def enakaTovora(tovor1, tovor2): ''' Ali sta tovora, podana v slovarjih tovor1 in tovor2 enaka''' # ali imata slovarja enako ključev (enako dolžino) if len(tovor1) != len(tovor2): return False # sedaj je dovolj, če preverimo, če so vsi ključi enega slovarja v drugem # in dajo isto vrednost for predmet, teza in tovor1.items(): # je predmet tudi v drugem slovarju if not predmet in tovor2: return False # sta teži v obeh slovarjih enaki if teza != tovor2[predmet]: return False # vsi testi so OK return True def enakaTovora(tovor1, tovor2): ''' Ali sta tovora, podana v slovarjih tovor1 in tovor2 enaka''' # lahko pa enostavno upoštevamo, da v objektu, ki ga vrne metoda items() # vrstni red ni pomemben, torej bosta slovarja enaka, če # bosta imela enaka items() return tovor1.items() == tovor2.items()
Sestavi funkcijo smiselenTovor(tovor, minTeža, maxTeža)
, ki "prečisti"
slovar z danimi težami tako, da vrne slovar, v katerem so le tisti predmeti,
katerih teža je med minTeža
in maxTeža
.
def smiselenTovor(tovor, minTeža, maxTeža): ''' vrne slovar, v katerem so le tisti predmeti, katerih teža je med minTeža in maxTeža ''' noviTovor = {} # pregledamo celoten tovor in v nov slovar dodamo predmete # z ustrezno težo for predmet, teža in tovor.items(): if minTeža <= teža <= maxTeža: noviTovor[predmet] = teža return noviTovor
Sestavi funkcijo najdaljšiOpis(tovor)
, ki vrne po abecedi urejen
seznam tistih predmetov, ki imajo najdaljši opis.
Za slovar iz zgleda bi torej dobili ['zaboj piva']
def najdaljšiOpis(tovor): ''' vrne po abecedi urejen seznam tistih predmetov, ki imajo najdaljši opis ''' # v seznam opisov dodamo '-' # Če bodo vsi predmeti imeli le enoznakovni opis, se bomo tega # na koncu po potrebi znebili seznamOpisov = ['-'] # enega potrebujemo, da bomo vedno primerjali s prvim iz # seznama kandidatov! for predmet in tovor: # je opis daljši? if len(predmet) > len(seznamOpisov[0]) : # seznamOpisov[0] vedno obstaja! seznamOpisov = [predmet] elif len(predmet) == len(seznamOpisov[0]) : # dodamo seznamOpisov.append(predmet) # je slučajno najdaljši opis dolg le en znak if len(seznamOpisov[0]) == 1: # "-" se moramo znebiti seznamOpisov = seznamOpisov[1:] return sorted(seznamOpisov)
Sestavi funkcijo najlažjiPredmet(tovor)
, ki vrne po abecedi urejen
seznam tistih predmetov, ki so najlažji.
Za slovar iz zgleda bi torej spet dobili ['zaboj piva']
, za prazen slovar
pa seveda vrnemo prazen seznam
def najlažjiPredmet(tovor): ''' vrne po abecedi urejen seznam tistih predmetov, ki so najlažji ''' if not tovor: # če je slovar prazen, vrnemo prazen seznam return [] # kandidat za najlažjega naj bo za 1 večja teža kot je prvi iz slovarja for predmet, teža in tovor.items(): najlažji = teža + 1 seznamNajlažjih = ['karkoli'] # tega na koncu tako ali tako ne bo! break # po prvem prehodu takoj zapustimo zanko # sedaj pa pregledujemo 'zares' for predmet, teža in tovor.items(): # je predmet lažji? if teža < najlažji : # nov kandidat za najlažjega seznamNajlažjih = [predmet] najlažji = teža elif teža == najlažji : # dodamo seznamNajlažjih.append(predmet) return sorted(seznamNajlažjih)
Substitucijska šifra je enostaven način šifriranja, pri katerem vsako črko iz dane abecede zamenjamo z neko drugo črko. Tako šifro predstavimo s slovarjem, ki ima za ključe vse črke iz abecede, pripadajoče vrednosti pa so črke, s katerimi jih zašifriramo.
Tako slovar {'A': 'B', 'C': 'C', 'B': 'D', 'D': 'A'}
pomenil, da se
A
zašifrira v B
, B
v D
, D
v A
, C
pa se ne spremeni.
Sestavi funkcijo sifriraj(sifra, beseda)
, ki vrne besedo, zašifrirano
z dano šifro. Predpostavite lahko, da vse črke v besedi nastopajo v
šifri.
def sifriraj(sifra, beseda): '''S slovarjem sifra zasifriramo besedo. Vrnemo niz, ki predstavlja ustrezno zašifrirano besedo.''' sezZasifCrk = [] for crka in beseda: # zašifriramo posamezno črko sezZasifCrk.append(sifra[crka]) return ''.join(sezZasifCrk) # vrnemo kot niz
Sestavi funkcijo jeSifra(slovar)
, ki ugotovi, ali slovar
predstavlja
šifro, torej ali je bijekcija črk na neki abecedi.
def jeSifra(slovar): '''Ali slovar predstavlja šifro''' # Pogledamo, če je množica ključev slovarja enaka množici vrednosti. # Ker so ključi v slovarju enolični, je velikost množice ključev enaka # kar številu črk v abecedi. Če sta torej množici ključev in vrednosti # enaki, je slovar surjektiven in s tem tudi injektiven. return set(slovar.keys()) == set(slovar.values())
Sestavi funkcijo inverz(sifra)
, ki vrne inverz dane šifre, če ta
obstaja. V nasprotnem primeru funkcija vrne None
.
def inverz(sifra): '''Vrni slovar, ki predstavlja obratno šifro, oziroma None, če ne gre''' if not jeSifra(sifra): return None inv = {} for k, v in sifra.items(): inv[v]=k return inv
Sestavi funkcijo odsifriraj(sifra, beseda)
, ki sprejme šifro in
zašifrirano besedilo, vrne pa odšifrirano besedilo. Če se besedila ne da
odšifrirati, naj funkcija vrne None
.
def odsifriraj(sifra, beseda): '''Vrnemo odšifrirano besedo, ki je bila šifrirana s šifro v slovarju sifra''' inv = inverz(sifra) if inv: # če inverz ne obstraja, dobimo None, kar se tolmači kot False return sifriraj(inv, beseda) else: return None # če inverza ni, ne moremo dešifrirati!
Zaradi napovedane prepovedi pisanja blagajniških računov na roko bodo v lokalni prodajalni prisiljeni preiti na računalniško podprto blagajno. Bazo prodajnih artiklov so pripravili v obliki slovarja, kjer je ključ ime artikla, vrednost pa par, ki vsebuje maloprodajno ceno in stopnjo davka (v procentih), na primer takole:
artikli = {
'ponev': (32.74, 22),
'knjiga': (18.60, 9.5),
'gugalnik': (153.22, 22),
'igrača': (12.18, 0),
'likalnik': (43.15, 9.5)
}
Tudi vsak izdan račun predstavimo v obliki slovarja. Ključ je ime kupljenega artikla, vrednost pa par, ki vsebuje količino (celo število) in popust (v procentih). Primeri:
racun1 = {'igrača': (2, 0), 'ponev': (1, 20), 'knjiga': (5, 10)}
racun2 = {'likalnik': (1, 5), 'igrača': (1, 20)}
racun3 = {'knjiga': (1, 0), 'igrača': (1, 0), 'ponev': (2, 20)}
Sestavite funkcijo davcna_osnova(mpc, ddv)
, ki bo za dano maloprodajno
ceno mpc
in stopnjo davka ddv
izračunala davčno osnovo, to je znesek,
na katerega zaračunamo davek, da dobimo maloprodajno ceno. Izračunano
davčno osnovo zaokrožite na dve decimalni mesti. Zgled:
>>> davcna_osnova(244.13, 22)
200.11
>>> davcna_osnova(1683.76, 9.5)
1537.68
def davcna_osnova(mpc, ddv): '''Davčna osnova glede na maloprodajno ceno in davek''' return round(mpc / (1 + ddv / 100), 2)
Sestavite funkcijo znesek_racuna(artikli, racun)
, ki izračuna, koliko
mora kupec plačati za kupljeno blago. Končni znesek zaokrožite na dve
decimalni mesti. Zgled:
>>> znesek_racuna(artikli, racun1)
134.25
Predpostavite, da so na računu le artikli, ki so v s slovarjem podani bazi artikli
def znesek_racuna(artikli, racun): '''Kaksen je znesek racuna za kupljene artikle. Racun je podan kot slovar, artikli pa je slovar s podatki o vseh artiklih''' vsota = 0 for artikel in racun: cena = artikli[artikel][0] kolicina = racun[artikel][0] popust = racun[artikel][1] znesek = kolicina * cena * (1 - popust / 100) vsota += znesek return round(vsota, 2)
Sestavite funkcijo davcni_obracun(artikli, racun)
, ki sestavi
specifikacijo davka za dani račun. Specifikacijo davka predstavimo
s slovarjem, kjer so ključi davčne stopnje, vrednosti pa vsote
davčnih osnov za kupljene artikle s takšno davčno stopnjo. Uporabite
funkcijo davcna_osnova
iz prve podnaloge! Končni zneski naj bodo
zaokroženi na dve decimalni mesti. Zgled:
>>> davcni_obracun(artikli, racun1)
{0: 24.36, 9.5: 76.44, 22: 21.47}
def davcni_obracun(artikli, racun): '''Vrne slovar s specifikacijo davka za dani račun''' obracun = {} for artikel in racun: cena = artikli[artikel][0] kolicina = racun[artikel][0] popust = racun[artikel][1] znesek = kolicina * cena * (1 - popust / 100) ddv = artikli[artikel][1] osnova = davcna_osnova(znesek, ddv) obracun[ddv] = obracun.get(ddv, 0) + osnova return obracun
Ob koncu delovnega dneva nas zanima, koliko katerega artikla smo prodali,
ločeno po različnih popustih, ki smo jih priznavali. Takšen dnevni obračun
predstavimo s slovarjem, kjer so ključi pari oblike (artikel, popust)
,
vrednosti pa ustrezne prodane količine tega artikla. Sestavite funkcijo
dnevni_obracun(artikli, racuni)
, ki bo za dani seznam računov sestavila
takšen dnevni obračun. Zgled:
>>> dnevni_obracun(artikli, [racun1, racun2, racun3])
{('ponev', 20): 3, ('likalnik', 5): 1, ('knjiga', 0): 1, ('igrača', 0): 3, ('knjiga', 10): 5, ('igrača', 20): 1}
def dnevni_obracun(artikli, racuni): '''Vrne slovar z dnevnim obračunom''' obracun = {} for racun in racuni: for artikel in racun: kolicina = racun[artikel][0] popust = racun[artikel][1] kljuc = (artikel, popust) # pazimo na ključ, ki še ni v slovarju obracun[kljuc] = obracun.get(kljuc, 0) + kolicina return obracun
Pri nas trenutno obstajajo tri davčne stopnje: višja, nižja in oproščena. Davčne stopnje so podane v slovarju, kjer so ključi vedno taki, kot kaže zgled davcne_stopnje = {'V': 22, 'N': 9.5, 'O': 0}
Lastnik popularne trgovinice (ki ima celo lastno pekarno), vas je najel, da mu napišete program za sestavljanje računov.
Nakupi so shranjeni v slovarju košarice, katerega ključi so imena kupcev, vrednosti pa slovarji predmetov in količin. Zgled:
kosarice = {'Janez': {'banana': 5, 'jogurt': 7},
'Mojca': {'francoska štrucka': 7}}
V tej trgovinici so francoske štručke zelo popularne. Vsak kupec vedno
kupi vsaj dve, tudi če tega nima zapisanega na nakupovalnem listku.
Sestavite funkcijo dodaj_strucke(kosarice)
, ki sestavi in vrne nov slovar, v
katerem ima vsak kupec poleg vsega, kar že ima, še vsaj po dve francoski
štručki. Zgled:
>>> kosarice = {'Janez': {'banana': 5, 'jogurt': 7}, 'Mojca': {'francoska štručka': 7}}
>>> dodaj_strucke(kosarice)
{'Janez': {'jogurt': 7, 'francoska štručka': 2, 'banana': 5},
'Mojca': {'francoska štručka': 7}}
def dodaj_strucke(kosarice): '''Vrne slovar z dodanimi francoskimi stručkami''' s_struckami = {} for kupec, nakup_prej in kosarice.items(): # za vsakega kupca vzamemo njegov nakupovalni listek s_struckami[kupec] = dict(nakup_prej) # dodamo kupca v nov slovar nakup = s_struckami[kupec] # nakupni listek tega kupca nakup['francoska štručka'] = nakup.get('francoska štručka', 2) # ohranimo fr. stručke, ali pa dodamo 2 return s_struckami # nakupovalni listki vseh kupcev
Šef trgovine je pripravil cenik vseh izdelkov, ki jih trgovinica
prodaja. Vsak izdelek ima par podatkov in sicer bruto ceno in davčno
stopnjo. Napišite funkcijo neto_in_davek(cenik, davcne_stopnje)
, ki sestavi in vrne nov slovar,
v katerem bo par podatkov in sicer: neto cena izdelka in davek, ki ga mora
trgovinica plačati držav, če so trenutno veljavne podane davčne stopnje.
Pri tem vse cene in davke (x) zaokroži z round(x,5)
.
Zgled:
>>> cenik = {'voda': (0.25, 'N'), 'sok': (1.20, 'V'), 'znamka A': (0.23, 'O')}
>>> neto_in_davek(cenik, {'V': 20, 'N': 8.5, 'O': 0})
{'sok': (1.0, 0.2), 'voda': (0.23041, 0.01959), 'znamka A': (0.23, 0.0)}
def neto_in_davek(cenik, davcne_stopnje): '''neto cena in davki''' neto_davek = {} for izdelek in cenik: bruto, stopnja = cenik[izdelek] neto = round(bruto / (1 + davcne_stopnje[stopnja] / 100), 5) neto_davek[izdelek] = (neto, round(bruto - neto,5)) return neto_davek
Sestavite funkcijo cene_z_ddv(kosarice, cenik, davcneStopnje)
, ki dobi slovar nakupov
in cenik (v originalni obliki), ter sestavi nov slovar nakupov, ki za
vsak nakup vsebuje peterico:
(kolicina, neto_na_enoto, neto_skupaj, davcna_stopnja, davek_skupaj)
(Ne pozabite upoštevati, da vsak kupi vsaj dve štručki.)
Pri tem vse cene in davke (x) zaokroži z round(x,5)
.
Zgled:
>>> cenik = {'voda': (0.25, 'N'), 'sok': (1.25, 'V'), 'znamka A': (0.23, 'O'),
'francoska štručka': (1, 'N')}
>>> kosarice = {'Janez': {'voda': 5, 'sok': 7},
'Mojca': {'francoska štručka': 7}}
>>> cene_z_ddv(kosarice, cenik)
{'Janez': {'sok': (7, 1.0, 7.0, 'V', 1.75), 'voda': (5, 0.22875, 1.14375, 'N', 0.10625),
'francoska štručka': (2, 0.915, 1.83, 'N', 0.17)},
'Mojca': {'francoska štručka': (7, 0.915, 6.405, 'N', 0.595)}}
def cene_z_ddv(kosarice, cenik, davcneStopnje): ''' ''' nakupi_ddv = dict() ddv_cenik = neto_in_davek(cenik, davcneStopnje) # izvemo neto cene in zneske davkov kosarice_s_struckami = dodaj_strucke(kosarice) # po potrebi dodamo štručke for kupec, nakup in kosarice_s_struckami.items(): nakupi_ddv[kupec] = dict() # slovar za tega kupca for artikel, kolicina in nakup.items(): neto_na_enoto = round(ddv_cenik[artikel][0], 5) neto_skupaj = round(neto_na_enoto * kolicina, 5) ddv_skupaj = round(ddv_cenik[artikel][1] * kolicina, 5) nakupi_ddv[kupec][artikel] = (kolicina, neto_na_enoto, neto_skupaj, cenik[artikel][1], ddv_skupaj) return nakupi_ddv
V nekem podjetju zbirajo podatke o osebah, ki brskajo po medmrežju. Podatki so shranjeni v slovarjih (en slovar za vsako osebo). Ključ v takem slovarju je lastnost, vrednosti pa podatek o tej lastnosti za določeno osebo. Primeri takšnih slovarjev:
oseba1 = {'ime': 'Božidar', 'telefon': '031918211',
'obiskane spletne strani': ['facebook.com', 'google.com']}
oseba2 = {'naslov': 'Dunajska 105', 'številka noge': 42,
'prijatelji': ['Marko', 'Ana']}
Sestavite funkcijo podatek(oseba, lastnost)
, ki vrne podatek o
lastnosti lastnost
, ki ga imamo v slovarju oseba
. Funkcija naj vrne
None
, če se ta podatek v slovarju ne nahaja. Primer:
>>> podatek({'ime': 'Božidar', 'naslov': 'Dunajska 105'}, 'naslov')
'Dunajska 105'
>>> podatek({'ime': 'Božidar', 'naslov': 'Dunajska 105'}, 'prijatelji')
None
Pri tem ne smeš uporabiti get!
def podatek(oseba, lastnost): '''Vrne podatek o lastnosti lastnost oz. None''' if lastnost not in oseba: return None return oseba[lastnost]
Sestavite funkcijo podatekGet(oseba, lastnost)
, ki vrne podatek o
lastnosti lastnost
, ki ga imamo v slovarju oseba
. Funkcija naj vrne
None
, če se ta podatek v slovarju ne nahaja. Primer:
>>> podatekGet({'ime': 'Božidar', 'naslov': 'Dunajska 105'}, 'naslov')
'Dunajska 105'
>>> podatekGet({'ime': 'Božidar', 'naslov': 'Dunajska 105'}, 'prijatelji')
None
Pri tem si nujno pomagajte z metodo get
def podatekGet(oseba, lastnost): '''Vrne podatek o lastnosti lastnost oz. None''' return oseba.get(lastnost, None)
Za osebi oseba1
in oseba2
pravimo, da se ujemata v lastnosti
lastnost
, če za obe osebi poznamo podatka o tej lastnosti in sta
podatka enaka. Če pa za obe osebi poznamo podatka in sta podatka
različna, pa pravimo, da se osebi razlikujeta v lastnosti lastnost
.
Na primer, osebi
oseba1 = {'ime': 'Janez', 'priimek': 'Novak'}
oseba2 = {'ime': 'Jože', 'priimek': 'Novak', 'starost': 20}
se ujemata v lastnosti 'priimek'
in razlikujeta v lastnosti 'ime'
.
(V lastnosti 'starost'
se niti ne ujemata niti ne razlikujeta.)
Sestavite funkcijo ujemanje(oseba1, oseba2)
, ki pove, v koliko
lastnostih se osebi oseba1
in oseba2
ujemata in v koliko lastnostih
se razlikujeta. Rezultat naj funkcija vrne kot seznam z dvema elementoma.
Primer:
>>> ujemanje({'ime': 'Janez', 'priimek': 'Novak'},
{'ime': 'Jože', 'priimek': 'Novak', 'starost': 20})
[1, 1]
def ujemanje(oseba1, oseba2): '''V koliko lastnostih se osebi ujemata in razlikujeta''' ujema = 0 razlikuje = 0 for lastnost in oseba1: # preverimo vse lastnosti prve osebe if lastnost in oseba2: # če gre za skupno lastnost if oseba1[lastnost] == oseba2[lastnost]: ujema += 1 else: razlikuje += 1 return [ujema, razlikuje]
Dva različna slovarja oseba1
in oseba2
lahko predstavljata isto
osebo. To se zgodi, če se slovarja ne razlikujeta v več kot 1 lastnosti
in se ujemata vsaj v 3 lastnostih ali če sta v obeh slovarjih lastnosti
ime
in priimek
enaki. Na primer, slovarja
oseba1 = {'ime': 'Janez', 'priimek': 'Novak', 'telefon': '031123234',
'starost': 90}
oseba2 = {'ime': 'Janez', 'priimek': 'Novak', 'davčna': '43424140'}
predstavljata isto osebo, prav tako slovarja
oseba1 = {'ime': 'Janez', 'priimek': 'Novak', 'telefon': '031123234',
'starost': 90}
oseba2 = {'ime': 'Luka', 'priimek': 'Novak', 'starost': 90,
'davčna': '43424140', 'telefon': '031123234'}
Sestavite funkcijo ista(oseba1, oseba2)
, ki preveri, ali slovarja
predstavljata isto osebo. Na primer, za zgornja primera mora funkcija
vrniti True
.
def ista(oseba1, oseba2): '''Ali gre ta isto osebo''' ujemata, razlikujeta = ujemanje(oseba1, oseba2) # uporaba funkcije prejšnje naloge je_ista = ujemata >= 3 and razlikujeta <= 1 if je_ista : return True # dovolj je že ujemanje v lastnostih! # če ni ujemanja v lastnostih, preverimo ime in priimek if 'ime' in oseba1 and 'ime' in oseba2 and 'priimek' in oseba1 and 'priimek' in oseba2: je_ista = (oseba1['ime'] == oseba2['ime'] and oseba1['priimek'] == oseba2['priimek']) return je_ista
V seznamu slovarjev, ki predstavljajo osebe, se lahko zgodi, da več slovarjev predstavlja isto osebo (isto v smislu prejšnje podnaloge). V takem primeru pravimo, da so ti slovarji podvojeni.
Sestavite funkcijo podvojeni(s)
, ki vrne seznam vseh podvojenih
slovarjev iz seznama s
. Slovarji naj bodo razvrščeni v istem vrstnem
redu kot v seznamu s
. Primer:
>>> podvojeni([{'ime': 'Jan', 'priimek': 'Dan', 'naslov': 'Jadranska 21'},
{'ime': 'Jan', 'priimek': 'Dan', 'naslov': 'Jadranska 19'},
{'ime': 'Žan', 'priimek': 'Dan', 'naslov': 'Jadranska 21'},
{'ime': 'Žan', 'priimek': 'Noč', 'naslov': 'Jamova 25'}])
[{'ime': 'Jan', 'priimek': 'Dan', 'naslov': 'Jadranska 21'},
{'ime': 'Jan', 'priimek': 'Dan', 'naslov': 'Jadranska 19'}]
def jeOsebaPodvojena(osb, s): '''Ali se oseba osb pojavi v seznamu s vsaj dvakrat''' kolikoIstih = 0 for oseba2 in s: # pogledamo vse osebe slovarja s if ista(osb, oseba2): # gre za isto osebo po kriterijih prej kolikoIstih += 1 return kolikoIstih >= 2 def podvojeni(s): '''Seznam vseh podvojenih oseb''' seznam = [] for oseba in s: # vsako osebo if jeOsebaPodvojena(oseba, s): # prevrimo, če je v seznamu oseba vsaj 2x seznam.append(oseba) return seznam
Sestavine, ki jih potrebujemo za nek recept, opišemo s slovarjem, v katerem so ključi sestavine, vrednosti pa količine, ki jih potrebujemo.
Sestavite funkcijo pomnozi(recept, faktor)
, ki sestavi in vrne nov
recept. Ta naj vsebuje iste sestavine kot recept recept
, le da so vse
količine v njem pomnožene z danim faktorjem.
>>> pomnozi({'jajca': 4, 'moka': 500}, 2)
{'jajca': 8, 'moka': 1000}
def pomnozi(recept, faktor): '''Vrne nov recept, spremenjen za faktor''' novR = dict() for sestavina, kolicina in recept.items(): novR[sestavina] = kolicina * faktor return novR def pomnoziV2(recept, faktor): '''Vrne nov recept, spremenjen za faktor''' # uporabimo izpeljane slovarje (dict comprehension) return {sestavina: kolicina * faktor for sestavina, kolicina in recept.items()}
Sestavite funkcijo imamoSestavine(recept, shramba)
, ki preveri, ali
imamo v shrambi dovolj sestavin za dani recept. Sestavine, ki jih imamo
v shrambi, so predstavljene s slovarjem na enak način kot sestavine v
receptu.
def imamoSestavine(recept, shramba): '''imamo v shrambi dovolj sestavin za dani recept''' for sestavina, kolicina in recept.items(): if shramba.get(sestavina, -1) < kolicina: # uporaba get, da ne dobimo izjeme pri neobstoječih sestavinah return False # že če ena manjka, ne gre return True # vsega imamo dovolj!
Sestavite funkcijo potrebnoKupiti(recept, shramba)
, ki vrne slovar
sestavin s pripadajočimi količinami, ki jih moramo še dokupiti, da bomo
lahko skuhali jed po danem receptu.
>>> potrebnoKupiti({'jajca': 3, 'moka': 500}, {'moka': 1000, 'jajca': 6, 'sladkor': 1000})
{}
>>> potrebnoKupiti({'jajca': 3, 'moka': 500}, {'moka': 1000, 'sladkor': 1000})
{'jajca': 3}
>>> potrebnoKupiti({'jajca': 3, 'moka': 500}, {'moka': 100})
{'jajca': 2, 'moka': 400}
def potrebnoKupiti(recept, shramba): '''vrne slovar sestavin s pripadajočimi količinami, ki jih moramo še dokupiti, da bomo lahko skuhali jed po danem receptu.''' kupiti = dict() for sestavina, kolicina in recept.items(): razlika = kolicina - shramba.get(sestavina, 0) # če sestavine še nimamo, je enako, kot če jo imamo 0! if razlika > 0: kupiti[sestavina] = razlika return kupiti
Niz je antipalindrom, kadar ima znake na vseh mestih različne od svojega
obrata. Tako je beseda mama
antipalindrom, saj se noben znak ne ujema
z znakom na istem mestu v besedi amam
, beseda anketa
pa ni antipalindrom,
saj ima prvem in zadnjem mestu enako črko kot njen obrat atekna
.
Sestavite funkcijo jeAntipalindrom(niz)
, ki vrne True
, če je niz
antipalindrom, in False
če ni.
def jeAntipalindrom(niz): '''Ali je niz antipalnidrom''' dolNiz = len(niz) if dolNiz % 2 == 1: # vsi lihi nizi zagotovo niso antipalidromi! return False for ind in range(dolNiz // 2): # preverimo prvih pol znakov (pazi if niz[ind] == niz[dolNiz - 1 - ind] : # primerjamo znake začetnega in končnega dela return False return True # vsi Testi so bili uspešni def jeAntipalindromV2(niz): '''Ali je niz antipalnidrom''' # uporaba naprednejših metod # V dokumentaciji si oglej all in zip return all(z1 != z2 for z1, z2 in zip(niz, niz[::-1]))
Sestavite funkcijo vsebovaniAntipalindromi(niz)
, ki vrne množico vseh
strnjenih podnizov niza niz
, ki so antipalindromi.
def vsebovaniAntipalindromi(niz): '''Vrne množico podnizov niza niz, ki so antipalindromi''' antipalindromi = set() # naredimo vse možne podnize for i in range(len(niz)): for j in range(i + 1, len(niz)+1): podniz = niz[i:j] # uporabimo funkcijo gornje naloge if jeAntipalindrom(podniz): # je anitiPalindrom, ga dodamo antipalindromi.add(podniz) return antipalindromi
Za razliko od običajnih družabnih omrežij, deluje nedružabno omrežje Hatebook tako, da si v omrežje vsak dodaja svoje sovražnike. Omrežje predstavimo s slovarjem, pri čemer so ključi osebe, vrednosti pa množice oseb, ki jih te osebe sovražijo.
Sestavite funkcijo seSovrazita(omrezje, oseba1, oseba2)
, ki vrne True
,
kadar osebi sovražita druga drugo, in False
sicer.
def seSovrazita(omrezje, oseba1, oseba2): '''Ali se osebi sovražita''' # oba ključa morata biti v seznamu vrednosti za drug ključ! return oseba1 in omrezje[oseba2] and oseba2 in omrezje[oseba1]
Sestavite funkcijo kdoSovrazi(omrezje, oseba)
, ki vrne množico oseb,
ki v danem omrežju sovražijo dano osebo.
def kdoSovrazi(omrezje, oseba): '''vrne množico oseb, ki v danem omrežju sovražijo dano osebo ''' kdoSovraži = set() for sovrag, sovrazniki in omrezje.items(): if oseba in sovrazniki: kdoSovraži.add(sovrag) return kdoSovraži def kdoSovraziV2(omrezje, oseba): '''vrne množico oseb, ki v danem omrežju sovražijo dano osebo ''' # uporaba izpeljanih množic (set comprehension) return {sovrag for sovrag, sovrazniki in omrezje.items() if oseba in sovrazniki}
Sestavite funkcijo nesrecniki(omrezje)
, ki vrne množico oseb, ki
sovražijo same sebe.
def nesrecniki(omrezje): '''Vrne množico oseb, ki sovražijo sebe''' mnNesrečnikov = set() for oseba, sovrazniki in omrezje.items(): if oseba in sovrazniki: mnNesrečnikov.add(oseba) return mnNesrečnikov def nesrecnikiV2(omrezje): '''Vrne množico oseb, ki sovražijo sebe''' # uporaba izpeljanih množic return {oseba for oseba, sovrazniki in omrezje.items() if oseba in sovrazniki}
Sestavite funkcijo najboljZadrti(omrezje)
, ki vrne množico vseh oseb,
ki v danem omrežju sovražijo največ oseb.
def najboljZadrti(omrezje): '''vrne množico vseh oseb, ki v danem omrežju sovražijo največ oseb''' najvec = 0 for sovrazniki in omrezje.values(): najvec = max(len(sovrazniki), najvec) # večjega od trenutnega kandidata in naj doslej # in še izpeljanih množic mnZadrtih = set() for oseba, sovrazniki in omrezje.items(): if len(sovrazniki) == najvec: mnZadrtih.add(oseba) return mnZadrtih def najboljZadrtiV2(omrezje): '''vrne množico vseh oseb, ki v danem omrežju sovražijo največ oseb''' #uporaba izpeljaniega ponovnika najvec = max(len(sovrazniki) for sovrazniki in omrezje.values()) # in še izpeljanih množic return {oseba for oseba, sovrazniki in omrezje.items() if len(sovrazniki) == najvec}
Sestavite funkcijo unijaSlovarjev(seznam_slovarjev)
, ki bo iz
danega seznama slovarjev sestavila nov slovar, ki bo predstavljal
unijo posameznih slovarjev. Vrednosti ključev v uniji slovarjev naj bodo
seznami vrednosti, ki pripadajo enakim ključem iz vhodnih slovarjev. Vrednosti naj bodo v
seznamih zapisane v enakem vrstnem redu, kot nastopajo v seznamu slovarjev.
Zgled:
>>> unija_slovarjev([{1: 2, 5: 0}, {2: 3, 5: 6, 7: 3}, {2: 3, 8: 1, 5: 4}])
{1: [2], 5: [0, 6, 4], 2: [3, 3], 7:[3], 8:[1]}
def unijaSlovarjev(seznamSlovarjev): '''Vrnemo slovar, ki je unija slovarjev''' novSlovar = dict() for slovar in seznamSlovarjev: # obdelamo vse slovarje for kljuc in slovar: if kljuc in novSlovar: # če se je ta ključ že pojavil novSlovar[kljuc].append(slovar[kljuc]) # dodamo njegovo vrednost else: novSlovar[kljuc] = [slovar[kljuc]] # sicer pa je to nov ključ return novSlovar
Patrik je za vse električne naprave, ki jih ima doma, ugotovil ime proizvajalca in podatke shranil v slovar. Zgled takega slovarja:
naprave = {
'hladilnik': 'Gorenje', 'pralni stroj': 'Whirlpool',
'kavni mlinček': 'Bosch', 'mikrovalovna pečica': 'Gorenje',
'parni čistilnik': 'Philips', 'laserski tiskalnik': 'Lexmark',
'sušilnik las': 'Philips'
}
Njegov sosed Darko pa je iz čistega dolgčasa sestavil slovar, v katerem so ključi naprave, vrednosti pa kategorije, kamor te naprave sodijo. Zgled:
kategorije = {
'hladilnik': 'bela tehnika', 'parni čistilnik': 'sesalniki',
'grelnik vode': 'kuhinjski aparati', 'pralni stroj': 'bela tehnika',
'sušilnik las': 'nega las', 'mikrovalovna pečica': 'kuhinjski aparati',
'laserski odstranjevalec dlačic': 'brivniki in depilatorji'
}
Patrik in Darko bi rada združila podatke in za vsako blagovno znamko,
ki se pojavi v Patrikovem slovarju, ugotovila, katere kategorije naprav
"pokriva" glede na Darkov slovar. Napišite funkcijo
blagovne_znamke(naprave, kategorije)
, ki vrne slovar, kjer so ključi
imena proizvajalcev, njihove pripadajoče vrednosti pa so množice
kategorij, s katerimi se proizvajalec ukvarja.
Naj bosta slovarja naprave
in kategorije
enaka kot zgoraj. Zgled:
>>> blagovne_znamke(naprave, kategorije)
{'Lexmark': set(), 'Philips': {'sesalniki', 'nega las'}, 'Whirlpool': {'bela tehnika'},
'Gorenje': {'bela tehnika', 'kuhinjski aparati'}, 'Bosch': set()}
Bodite pozorni na to, da se lahko v Patrikovem slovarju pojavijo tudi naprave, ki jih Darko nima v svojem slovarju, in obratno.
def blagovne_znamke(naprave, kategorije): '''vrne slovar, kjer so ključi imena proizvajalcev, njihove pripadajoče vrednosti pa so množice kategorij, s katerimi se proizvajalec ukvarja.''' blagZnamke = dict() for naprava, znamka in naprave.items(): if znamka not in blagZnamke: blagZnamke[znamka] = set() # nova znamka, začnemo s prazno množico if naprava in kategorije: blagZnamke[znamka].add(kategorije[naprava]) # dodamo vse ustrezne kategorije return blagZnamke
Dan je slovar, ki slika ključe xi
(ključi so nizi)
v celoštevilske vrednosti vi
, recimo
{'foo':1, 'bar':7, 'baz':100, 'qux':20, 'quux':30}
Sestavi funkcijo ključZNajVrednostjo(sl)
, ki sprejme tak slovar
in vrne tisti ključ xi
, ki ima
največjo pripadajočo vrednost vi
. Če bi na primer poklicali funkcijo
s prejšnjim slovarjem, bi dobili rezultat 'baz'
.
Če je slovar prazen, vrni None
.
Predpostavi, da je le en ključ z največjo vrednostjo.
def ključZNajVrednostjo(sl): ''' vrne tisti ključ `xi`, ki ima največjo pripadajočo vrednost `vi`.''' if not sl: # če je prazen return None # za kandidata vzamemo vrednost prvega iz slovarja for kl, vr in sl.items(): najVr = vr najKljuč = 'Žal bom izginil' break # rabimo le prvega # sedaj pa zares for kl, vr in sl.items(): if vr >= najVr: # našli smo boljšega najVr = vr najKljuč = kl return najKljuč
Sedaj pa spustimo omejitev, da obstaja le en ključ z največjo vrednostjo.
Sestavi funkcijo seznamKljučevZNajVrednostjo(sl)
, ki vrne po
abecedi urejen seznam vseh ključev z največjo vrednostjo.
Če je slovar prazen, vrni prazen seznam.
def seznamKljučevZNajVrednostjo(sl): ''' vrne po abecedi urejen seznam tisti ključev `xi`, ki imajo največjo pripadajočo vrednost `vi`.''' if not sl: # če je prazen return [] # za kandidata vzamemo vrednost prvega iz slovarja - 1 for kl, vr in sl.items(): najVr = vr - 1 najKljuč = [] break # rabimo le prvega # sedaj pa zares for kl, vr in sl.items(): if vr > najVr: # našli smo boljšega najVr = vr najKljuč = [kl] elif vr == najVr: # našli smo enako dobrega najKljuč.append(kl) return sorted(najKljuč)
prosto po Tavčarju ;-) ali po Galetu
Socialno omrežje zaljubljenosti podamo s slovarjem, ki ime osebe preslika v seznam vseh, v katere je oseba zaljubljena (ena oseba je lahko zaljubljena v več oseb). Na primer, slovar
s = {'Ana' : ['Bine','Cene'],
'Bine' : [],
'Cene' : ['Bine', 'Cene'],
'Davorka' : ['Davorka'],
'Eva' : ['Bine']}
nam pove, da je Ana zaljubljena v Bineta in Cenete, Bine ni zaljubljen, Cene ljubi Bineta in samega sebe, Davorka samo sebe in Eva Bineta.
Sestavite funkcijo narcisoidi(d)
, ki sprejme slovar zaljubljenih
in vrne po abecedi urejen seznam tistih, ki ljubijo same sebe.
def narcisoidi(d): '''Vrne po abecedi urejen seznam narcisoidov''' sezNar = [] for oseba in d: if oseba in d[oseba]: # ta bo pravi! sezNar.append(oseba) return sorted(sezNar) def narcisoidiV2(d): '''Vrne po abecedi urejen seznam narcisoidov''' # uporabimo izpeljane sezname (list comprehension) return sorted([oseba for oseba in d if oseba in d[oseba]])
Sestavite funkcijo ljubljeni(d)
, ki sprejme slovar zaljubljenih
in vrne po abecedi urejen seznam tistih, ki so ljubljeni.
def ljubljeniV2(d): '''Vrne po abecedi urejen _seznam_ tistih, ki so ljubljeni''' # naredimo s seznamom seznamOseb = list() for oseba in d: # za vse osebe for ljubljen in d[oseba]: # dodamo njihove ljubljene (če je potrebno) if ljubljen not in seznamOseb: # če še niso seznamOseb.append(ljubljen) return sorted(seznamOseb) def ljubljeni(d): '''Vrne po abecedi urejen _seznam_ tistih, ki so ljubljeni''' mnLjubljenih = set() for oseba in d: # za vse osebe mnLjubljenih.update(d[oseba]) # dodamo vse ljubljene te osebe return sorted(mnLjubljenih) # sorted vrne urejen seznam - argument je lahko poljubni iterator
Sestavite funkcijo pari(d)
, ki sprejme slovar zaljubljenih
in vrne seznam vseh parov, ki so srečno ljubljeni. Vsak
par naj se pojavi samo enkrat in sicer tako, da je sta zaljubljenca
našteta po abecedi. Na primer, če sta Ana in Bine zaljubljena,
dodamo par ('Ana','Bine')
.
def pari(d): '''Po abecedi urejen par srečno ljubljenih - torej takioh, ki ljubijo osebo, ki ljubi njih''' seznamParov = [] for oseba in d: # za vsako osebo, ki jo ljubi, pogledamo, če ta ljubi njega for ljubljeni in d[oseba]: if oseba in d[ljubljeni] : # ga bomo dodali urejenPar = tuple(sorted([oseba,ljubljeni])) # a le , če že ni notri if urejenPar not in seznamParov: # namig - namesto seznama bi lahko uporabili množico in bi ta stavek if odpadel seznamParov.append(urejenPar) return sorted(seznamParov)
Sestavite funkcijo ustrezljivi(oseba, d)
, ki sprejme ime osebe ter
slovar zaljubljenih, vrne pa po abecedi urejen seznam vseh ljudi, ki so do dane osebe
še posebej ustrežljivi. Posebej ustrežljivi so seveda za to, ker so
bodisi zaljubljeni v dano osebo, bodisi so zaljubljeni v osebo, ki je
posebej ustrežljiva do nje, in tako naprej.
Na primer, če imamo slovar
s = {'Ana' : ['Bine', 'Cene'],
'Bine' : ['Ana'],
'Cene' : ['Bine'],
'Davorka' : ['Davorka'],
'Eva' : ['Bine']}
so do Ceneta posebej ustrežljivi Ana (ki je zaljubljena vanj), Bine (ki je zaljubljen v Ano), Eva (ki je zaljubljena v Bineta), ter seveda Cene, ki je zaljubljen v Evo.
def ustrezljiviV2(oseba, d): '''vrne po abecedi urejen _seznam_ vseh ljudi, ki so do dane osebe še posebej ustrežljivi''' # seznam, v katerega nabiramo ustrežljive osebe ustrezljivi = [] # najprej dodamo tiste, ki ljubijo prvo osebo dodani = [o for o in d if oseba in d[o]] # dokler smo koga dodali, dodajamo ustrežljive while dodani: for nekdo in dodani: if nekdo not in ustrezljivi: # če ga še ni noter ustrezljivi.append(nekdo) # sedaj pa dodajamo tiste, ki ljubijo nazadnje dodane osebe dodani = [o for o in d for dodan in dodani if dodan in d[o] and o not in ustrezljivi] return sorted(ustrezljivi) def ustrezljivi(oseba, d): '''vrne po abecedi urejen _seznam_ vseh ljudi, ki so do dane osebe še posebej ustrežljivi''' # seznam, v katerega nabiramo ustrežljive osebe ustrezljivi = [] # najprej dodamo tiste, ki ljubijo prvo osebo dodani = [] for nekdo in d: if oseba in d[nekdo]: dodani.append(nekdo) # dokler smo koga dodali, dodajamo ustrežljive while dodani: for nekdo in dodani: if nekdo not in ustrezljivi: # če ga še ni noter ustrezljivi.append(nekdo) # sedaj pa dodajamo tiste, ki ljubijo nazadnje dodane osebe noviDodani = [] for o in d: for nekdo in dodani: if nekdo in d[o] and o not in ustrezljivi: noviDodani.append(o) dodani = noviDodani[:] return sorted(ustrezljivi)
Pri tej nalogi boste napisali funkcijo, ki bo za dano število vrnila niz z ustrezno rimsko številko. Nato boste napisali še funkcijo, ki bo rimsko številko spremenila nazaj v število.
Preden začnete, si na oglejte članek o rimskih številkah na Wikipediji: Rimske številke.
Napišite funkcijo vRimsko(stevilo)
, ki kot argument dobi celo
število med 1 in 3999 (vključno z 1 in 3999). Funkcija naj sestavi
in vrne niz, ki vsebuje rimsko številko, ki predstavlja število stevilo
.
Zgled:
>>> vRimsko(2013)
'MMXIII'
def vRimsko(stevilo): '''Iz 'običajnega' zapisa števila med 1 in 3999 naredimo rimski zapis števila ''' tabelaRimskih = [ ['', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'], ['', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC'], ['', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM'], ['', 'M', 'MM', 'MMM']] rimsko = '' for i in range(4): rimsko = tabelaRimskih[i][stevilo%10] + rimsko stevilo //= 10 return rimsko
Napišite še funkcijo vArabsko(niz)
, ki bo dobila niz niz
, ki
predstavlja rimsko številko. Funkcija naj naredi ravno obratno kot
funkcija vRimsko
, tj. vrne naj ustrezno število, ki ga predstavlja
dana rimska številka. Če niz
ne predstavlja veljavnege rimske
številke, naj funkcija vrne None
. Zgled:
>>> vArabsko('MMXIII')
2013
Nasvet: Najprej sestavi slovar, ki kot ključe vsebuje rimske številke, kot vrednosti pa ustrezna števila. Potem le uporabi ta slovar.
def vArabsko(niz): '''Iz rimskega zapisa naredimo arabski zapis števila Če ne gre, vrnemo None. ''' tabelaRimskih = [ ['', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX'], ['', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC'], ['', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM'], ['', 'M', 'MM', 'MMM']] slovarRimskih = {vRimsko(i):i for i in range(1, 4000)} if niz not in slovarRimskih: return None return slovarRimskih[niz]
Ukvarjali se bomo z rodovniki (Celjskih grofov in drugih). Rodovnik imamo podan kot slovar, kjer je ključ ime "glave rodbine" vrednost pa seznam imen otrok. Recimo:
rodovnik =
{'Ulrik I.': ['Viljem'], 'Margareta': [], 'Herman I.': ['Herman II.', 'Hans'],
'Elizabeta II.': [], 'Viljem': ['Ana Poljska'], 'Elizabeta I.': [],
'Ana Poljska': [], 'Herman III.': ['Margareta'], 'Ana Ortenburška': [],
'Barbara': [], 'Herman IV.': [], 'Katarina': [], 'Friderik III.': [],
'Herman II.': ['Ludvik', 'Friderik II.', 'Herman III.', 'Elizabeta I.', 'Barbara'],
'Ulrik II.': ['Herman IV.', 'Jurij', 'Elizabeta II.'], 'Hans': [], 'Ludvik': [],
'Friderik I.': ['Ulrik I.', 'Katarina', 'Herman I.', 'Ana Ortenburška'],
'Friderik II.': ['Friderik III.', 'Ulrik II.'], 'Jurij': []}
rodovnik['Friderik II.']
nam torej vrne
['Friderik III.', 'Ulrik II.']
Število otrok
Sestavi funkcijo kolikoOtrok(ime, rodovnik)
, ki za dano ime in
rodovnik vrne število otrok te osebe, oz None, če osebe ni v rodovniku.
def kolikoOtrok(ime, rodovnik) : ''' koliko otrok ima oseba z imenom ime ''' if ime not in rodovnik: return None return len(rodovnik[ime])
Število potomcev
Sestavi funkcijo kolikoPotomcev(ime, rodovnik)
, ki za dano ime
in
rodovnik
vrne število potomcev te osebe. Če osebe ni v rodovniku, vrni None
def kolikoPotomcev(ime, rodovnik) : ''' koliko potomcev ima oseba z imenom ime ''' if ime not in rodovnik: # če je slučajno ni return None otroci = rodovnik[ime] kolikoJihJe = len(otroci) # potomci so otroci for oseba in otroci: # in vsi potomci otrok kolikoJihJe += kolikoPotomcev(oseba, rodovnik) return kolikoJihJe
Je v rodbini?
Sestavi funkcijo jeTaVRodbini(ime, glavaRodbine, rodovnik)
, ki ugotovi, ali
je oseba z imenom ime
v rodbini osebe glavaRodbine
.
def jeTaVRodbini(ime, glavaRodbine, rodovnik) : ''' Ali je oseba z imenom ime v rodbini osebe glavaRodbine ''' if ime == glavaRodbine: # če je to že kar "šef" return True # je morda med otroci otroci = rodovnik[glavaRodbine] if ime in otroci : # pravzaprav je ta stavek if odveč. Zakaj? Premisli! return True # je morda v rodbini otrok? for oseba in otroci : if jeTaVRodbini(ime, oseba, rodovnik) : return True # ni bil nikjer, torej ... return False
Kdo se podpisuje najdlje časa?
Sestavi funkcijo najdaljsiPodpis(glavaRodbine, rodovnik)
, ki ugotovi, kdo
v rodbini osebe glavaRodbine
ima najdaljše ime za podpis (torej kompletno ime).
def najdaljsiPodpis(glavaRodbine, rodovnik) : ''' kdo v rodbini osebe glavaRodbine ima najdaljše ime. ''' najIme = glavaRodbine # morda je to kar glava rodbine # je morda v rodbini otrok? otroci = rodovnik[glavaRodbine] for oseba in otroci : najMedOsebo = najdaljsiPodpis(oseba, rodovnik) if len(najMedOsebo) > len(najIme) : najIme = najMedOsebo return najIme
Kdo ima najkrajše ime?
Sestavi funkcijo najkrajseIme(glavaRodbine, rodovnik)
, ki ugotovi, kdo
v rodbini osebe glavaRodbine
ima najkrajše ime.
(šteje samo krstno ime, brez "Ortenburga" in "Celja" ter brez številk)?
def najkrajseIme(glavaRodbine, rodovnik) : ''' kdo v rodbini osebe glavaRodbine ima najkrajse ime. ''' # morda je to kar glava rodbine najIme = glavaRodbine.split()[0] # izrabimo dejstvo, da je "pravo" ime takoj na začetku ... # je morda v rodbini otrok? otroci = rodovnik[glavaRodbine] for oseba in otroci : najMedOsebo = najkrajseIme(oseba, rodovnik) if len(najMedOsebo) < len(najIme) : najIme = najMedOsebo return najIme
Globina rodbine
"Globino" rodbine definiramo tako: če nekdo nima otrok, je globina njegove rodbine 1. Če ima otroka, ta pa nima vnukov (ali celo več otrok, ti pa nimajo vnukov), je globina rodbine 2. Če nekdo ima vnuke, vendar nobenega pravnuka, je globina njegove rodbine 3.
Sestavi funkcijo globina(glavaRodbine, rodovnik)
, ki vrne globino rodbine
osebe glavaRodbine
v rodovniku rodovnik
def globina(glavaRodbine, rodovnik): '''Kakšna je globina rodbine osebe glavaRodbine''' # če nima otrok, je na globini 1 if rodovnik[glavaRodbine] == []: return 1 # ima vsaj enega otroka # potrebujemo globine vseh otrok te glaveRodbine glOtrok = [] for otrok in rodovnik[glavaRodbine]: # koliko je globina za tega otroka glOtroka = globina(otrok, rodovnik) glOtrok.append(glOtroka) # zanima nas le največja najGlOtrok = max(glOtrok) # globina glave rodbine je za 1 večja od tega maksimuma return 1 + najGlOtrok def globinaV2(glavaRodbine, rodovnik): '''Kakšna je globina rodbine osebe glavaRodbine brez uporabe funkcije max ''' # če nima otrok, je na globini 1 if rodovnik[glavaRodbine] == []: return 1 # ima vsaj enega otroka # potrebujemo maksimalno globino od vseh otrok te glaveRodbine najGlOtrok = 0 # ker so vse globine poz. števila, je začetni kandidat lahko 0 for otrok in rodovnik[glavaRodbine]: # koliko je globina za tega otroka glOtroka = globinaV2(otrok, rodovnik) if glOtroka > najGlOtrok: # našli smo boljšega kandidata najGlOtrok = glOtroka # globina glave rodbine je za 1 večja od tega maksimuma return 1 + najGlOtrok def globinaV3(oseba, rodovnik): otroci = rodovnik[oseba] if otroci: # če imamo otroke, je naša globina za 1 večja od naj globine naših otrok return 1 + max(globinaV3(otrok, rodovnik) for otrok in otroci) else: # drugače smo na globini 1 return 1
V nalogi se bomo igrali s slovarji, ki opisujejo, kje se nahaja kakšen kraj. Slovar je lahko recimo, tak
svet = {
"Evropa": {
"Slovenija": {
"Gorenjska": {
"Kranj": {},
"Radovljica": {},
"Zali log": {},
},
"Štajerska": {
"Maribor": {},
"Celje": {}
},
"Osrednja": {
"Ljubljana": {
"Vič": {
"FMF": {
"2.02": {
"tretja vrsta desno": {
"peti stol z desne": {
"Benjamin": {}
}
}
}
}
},
"Šiška": {}
}
}
},
"Nemčija": {
"Bavarska": {
"Munchen": {}
},
"Berlin": {}
},
},
"Amerika": {
"ZDA": {
"Teksas": {
"Houston": {},
"Austin": {}
},
"Kalifornija": {
"San Francisco": {}
},
"Anchorage": {}
},
"Kanada": {}
},
"Azija": {
"Osaka": {}
}
}
Ključi slovarja so torej nizi, vsebine pa so slovarji, ki so lahko tudi prazni. Namig: Oglejte si kako preveriti, ali je neka stuktura prazna,
Napiši funkcijo vrniVse(kraji)
, ki kot argument dobi slovar,
kakršen je gornji, in vrne po abecedi urejen seznam vseh krajev
in reči v njem.
def vrniVse(kraji): '''po abesedi urejen seznam vseh krajev in reči v slovarju ''' if not kraji : # če je slovar prazen return [] seznamVseh = [] for el in kraji: # dodamo ključ seznamVseh.append(el) # in vse elemente slovarja, ki je vrednost seznamVseh += vrniVse(kraji[el]) return sorted(seznamVseh)
Napiši funkcijo prestej(kraji)
, ki vrne število vseh krajev in
reči, ki se pojavijo v podanem slovarju.
def prestej(kraji): '''koliko je stvari v slovarju kraji''' # v praznem slovarju ni stvari if len(kraji) == 0: return 0 # pregledamo vse elemente slovarja in prištejemo 1 za ključ # in ustrezno število stvari v pripdajočem podslovarju koliko = 0 for slovar in kraji.values(): koliko += 1 # za ključ! kolikoVPodsl = prestej(slovar) koliko += kolikoVPodsl return koliko # načeloma je prvi stavek if odveč, zato lahko napišemo def prestejV2(kraji): '''koliko je stvari v slovarju kraji''' # pregledamo vse elemente slovarja in prištejemo 1 za ključ # in ustrezno število stvari v pripdajočem podslovarju koliko = 0 for slovar in kraji.values(): koliko += 1 # za ključ! kolikoVPodsl = prestejV2(slovar) koliko += kolikoVPodsl return koliko
Denimo, da imamo slovar (kot sta kraji
in svet
), ki kot vrednosti spet vsebuje
slovarje.
Sestavi funkcijo najSlovar(slovar)
, ki vrne tisti slovar,
ki vsebuje največ ključev.
def najSlovar(slovar) : ''' V slovarju slovarjev vrnemo slovar, ki vsebuje največ ključev ''' if not slovar : # če je slovar prazen return slovar #kandidat za največjega je kar ta slovar kanNajSlovar = slovar # morda se v kakšni vrednosti skriva večji slovar for kljuc in slovar: # pogledamo najSlovar v ustrezni vrednosti vrednost = slovar[kljuc] kandidat = najSlovar(vrednost) if len(kandidat) > len(kanNajSlovar) : # našli smo boljšega kanNajSlovar = kandidat return kanNajSlovar
Sestavi funkcijo jeVSlovarju(slovar, nekaj)
, ki ugotovi, ali je
v slovarju slovar
tudi niz nekaj
(bodisi kot ključ, bodisi kot vrednost)
def jeVSlovarju(slovar, nekaj) : ''' Ali je v slovarju slovar tudi niz nekaj (bodisi kot ključ, bodis kot vrednost)''' if not slovar : # če je slovar prazen return False # pregledamo vse ključe for kljuc in slovar: # pogledamo če je morda to ta ključ if kljuc == nekaj: return True # je morda v vrednosti, ki je slovar if jeVSlovarju(slovar[kljuc], nekaj): return True # nekaj ni bil ne ključ, en v kateri od vrenosti, torej je ni! return False
Sestavi funkcijo vrniVrednost(slovar, nekaj)
, ki vrne tisto vrednost
iz slovarja slovarjev slovar
, ki pripada ključu nekaj
Če pa v slovarju slovarjev nekaj
ni ključ, naj vrne None
def vrniVrednost(slovar, nekaj) : ''' Ali je v slovarju slovar tudi niz nekaj (bodisi kot ključ, bodis kot vrednost)''' if not slovar : # če je slovar prazen return None # pregledamo vse ključe for kljuc in slovar: # pogledamo če je morda to ta ključ if kljuc == nekaj: return slovar[kljuc] # je morda v vrednosti, ki je slovar kaj = vrniVrednost(slovar[kljuc], nekaj) if kaj != None : # torej je bilo return kaj # nekaj nismo našli v nobenem slovarju, torej je ni! return None
V nekem uspešnem podjetju ima skoraj vsak zaposleni svojega šefa. Seveda imajo tudi šefi svoje šefe in ti spet svoje šefe itn. Dobili smo podatke o hierarhiji v podjetju in ugotovili, da velja naslednje:
Napisali bomo nekaj funkcij, s katerimi bomo preučili razmere v podjetju.
Podatke smo dobili v obliki seznama parov oblike (uslužbenec, šef)
.
Vsi uslužbenci so predstavljeni z nizi (ki so običajno njihova imena oz.
priimki). Zgled:
[('Mojca', 'Tilen'), ('Andrej', 'Tilen'), ('Tilen', 'Zoran')]
Komentar: Tilen ima pod seboj dva podrejena (Andreja in Mojco), njegovi šef pa je Zoran. Zoran nima šefa, vsi ostali pa so njegovi podrejeni.
Napišite funkcijo slovarSefov(seznam)
, ki bo iz zgoraj opisanega
seznama zgradila slovar šefov. Ključi v seznamu naj bodo uslužbenci,
vrednosti pa njihovi šefi. Zgled:
>>> slovarSefov([('Mojca', 'Tilen'), ('Andrej', 'Tilen'), ('Tilen', 'Zoran')])
{'Andrej': 'Tilen', 'Mojca': 'Tilen', 'Tilen': 'Zoran'}
def slovarSefov(seznam): '''Glede na zgornji opis vrne slovar šefov''' slovar = {} for usluzbenec, sef in seznam: slovar[usluzbenec] = sef return slovar
Napišite funkcijo neposrednoPodrejeni(seznam)
, ki bo iz zgoraj opisanega
seznama sestavila slovar neposredno podrejenih. Vrednost pri vsakem
ključu naj bo množica tistih uslužbencev, ki imajo le-ta ključ za svojega
šefa. Zgled:
>>> neposrednoPodrejeni([('Mojca', 'Tilen'), ('Andrej', 'Tilen'), ('Tilen', 'Zoran')])
{'Zoran': {'Tilen'}, 'Tilen': {'Andrej', 'Mojca'}}
Zoranu je torej neposredno podrejen le Tilen, Tilnu pa sta podrejena tako Andrej kot Mojca.
def neposrednoPodrejeni(seznam): '''Glede na zgornji opis vrne slovar šef : množica neposredno podrejenih''' podrejeni = {} for usluzbenec, sef in seznam: # sprehodimo se po parih iz seznama if sef not in podrejeni: # če smo našli novega šefa podrejeni[sef] = set() # je potrebno narediti nov vnos v slovar podrejeni[sef].add(usluzbenec) return podrejeni
Sestavite funkcijo verigaNadrejenih(usluzbenec, slovar)
, ki kot prvi
argument dobi niz, ki predstavlja nekega uslužbenca, kot drugi argument
pa dobi slovar šefov (v obliki kot ga vrne funkcija slovarSefov
).
Funkcija naj sestavi seznam, ki po vrsti vsebuje: šefa osebe usluzbenec
,
šefa od njegovega šefa itn. (dokler končno ne pridemo do osebe, ki nima šefa).
Zgled:
>>> verigaNadrejenih('Mojca', {'Andrej': 'Tilen', 'Mojca': 'Tilen', 'Tilen': 'Zoran'})
['Tilen', 'Zoran']
Mojci je nadrejen Tilen, kateremu je nadrejen Zoran, torej sta Mojčina šefa Tilen in Zoran.
def verigaNadrejenih(usluzbenec, slovar): '''sestavi seznam, ki predstavlja verigo nadreejenih''' # če oseba nima šefa, je njegova veriga prazna # oseba nima šefa, če se ne pojavi kot ključ if usluzbenec not in slovar.keys(): return [] # uslužbenec ima šefa! sef = slovar[usluzbenec] seznamNadrejenih = [sef] # določimo verigo nadrejenih od šefa verNadrSef = verigaNadrejenih(sef, slovar) # združimo seznama seznamNadrejenih = seznamNadrejenih + verNadrSef return seznamNadrejenih def verigaNadrejenihV2(usluzbenec, slovar): '''Glede na zgornji opis vrne zaporedni seznam oseb, ki so uslužbencu nadrejeni''' '''brez rekurzije''' veriga = [] while usluzbenec in slovar: # če uslužbenec ima šefa (ko ga ne bo imel, smo na koncu verige!) usluzbenec = slovar[usluzbenec] # vzamemo njegovega šefa - v naslednjem koraku bomo vzeli njegovega šefa ... veriga.append(usluzbenec) # in ga dodamo return veriga
Sestavite funkcijo mnozicaPodrejenih(usluzbenec, slovar)
, ki kot prvi
argument dobi ime uslužbenca, kot drugi argument pa slovar neposredno
podrejenih (v obliki kot ga vrne funkcija neposrednoPodrejeni
). Funkcija
naj sestavi in vrne množico vseh tistih oseb, ki so (posredno ali
neposredno) podrejeni osebi usluzbenec
. Zgled:
>>> mnozicaPodrejenih('Zoran', {'Zoran': {'Tilen'}, 'Tilen': {'Andrej', 'Mojca'}, 'Mojca' : {'Urša'}})
{'Andrej', 'Mojca', 'Tilen', 'Urša'}
Zoranju je neposredno podrejen Tilen, torej sta mu podrejena tudi Tilnova podrejena Andrej in Mojca, ter Urša, ker je ta podrejena Mojci.
def mnozicaPodrejenih(usluzbenec, slovar): '''vrne _množico_ vseh tistih oseb, ki so (posredno ali neposredno) podrejeni osebi `usluzbenec`.''' # komentarjev NAMENOMA ni ! dodaj = [usluzbenec] podrejeni = set() while len(dodaj) > 0: u = dodaj[-1] del dodaj[-1] if u not in slovar: continue for v in slovar[u]: if v not in podrejeni: dodaj.append(v) podrejeni.add(v) return podrejeni
Tistemu uslužbencu, za katerega velja:
pravimo big boss. Sestavite funkcijo bigBoss(slovar)
, ki kot argument
dobi slovar nadrejenih in vrne ime osebe, ki je big boss v podjetju oz.
vrednost None
, če to podjetje nima big boss-a. Zgled:
>>> bigBoss({'Andrej': 'Tilen', 'Mojca': 'Tilen', 'Tilen': 'Zoran'})
'Zoran'
def bigBoss(slovar): '''nekdo, ki nima šefa in je šef vsem ostalim''' if len(slovar) == 0: return None # tak slovar ga nima! bigBoss = list(slovar.keys())[0] # kandidat za velikega šefa (če ne bo imel nadrejenih!) nadrejeni = verigaNadrejenih(bigBoss, slovar) # kdo so kandidatu nadrejeni? if len(nadrejeni) > 0: # če je prejšnji kandidat imel nadrejene bigBoss = nadrejeni[-1] # je samo zadnji kandidat za velikega šefa # dobili smo kandidata za big boss-a for uslužbenec in slovar: # pregledamo vse uslužbence if uslužbenec == bigBoss: # kandidata spustimo continue nadrejeni = verigaNadrejenih(uslužbenec, slovar) # pogledamo vse uslužbencu nadrejene if (len(nadrejeni) == 0) or (nadrejeni[-1] != bigBoss): # če jih ni, potem bigBNoss ni nadrejeni temu, torej ni veliki šef! return None # ali pa najvišji nadrejeni temu uslužbencu ni bil naš veliki šef - v firmi velikega šefa ni return bigBoss
Ker ste v komentarjih napisali, da je ukvarjanje s permutacijami vaša najbolj priljubbljena tema, se permutacije vračajo v vsem svojem sijaju!
V slovarju imamo shranjeno permutacijo naravnih števil od {1: 3, 2: 2, 3: 1}
.
Pri vseh nalogah predpostavite, da je število x zagotovo element permutacije. Prav tako tudi to, da je permutacija pravilna.
Le za ogrevanje (naloga "ne šteje") rešite naslednjo nalogo:
Sestavite funkcijo slika(permutacija, x)
, vrne pa sliko števila x
s podano permutacijo.
def slika(permutacija, x): return permutacija[x]
Sestavite funkcijo jePermutacija(slovar)
, ki vrne True
, če dan
slovar predstavlja permutacijo, in False
sicer.
Npr. slovar {1: 3, 3: 1}
ni permutacija, saj ne vemo, kam se slika 2. Tudi {1: 3, 2: 2, 3: 2, 4: 1}
ni slovar, saj 4 ni slika nobenega števila!
def jePermutacija(slovar): # Za vsa števila od 1 do n bomo pogledali, če nastopajo tako v domeni # kot v sliki permutacije. Imeli bomo seznam je_v_domeni, ki ima na # mestu i - 1 zapisano, če smo ugotovili, da i je v domeni permutacije. # Podobno storimo za sliko. n = len(slovar) je_v_domeni = [False for i in range(n)] je_v_sliki = [False for i in range(n)] # Nato gremo čez vse ključe k in pripadajoče vrednosti v v slovarju. # Če sta tako k kot v med 1 in n, označimo, da sta v domeni in sliki, # sicer pa vemo, da slovar ne predstavlja permutacije. for k, v in slovar.items(): if 1 <= k <= n and 1 <= v <= n: je_v_domeni[k - 1] = True je_v_sliki[v - 1] = True else: return False # Na koncu pogledamo, ali so v domeni in sliki nastopala vsa števila. # Funkcija all vrne True natanko takrat, ko so vsi elementi v seznamu # enaki True. return all(je_v_domeni) and all(je_v_sliki)
Sestavite funkcijo slike(permutacija, x, n)
, ki vrne zaporedje slik,
ki ga dobimo, če začnemo s številom x
in na njem n
-krat uporabimo
permutacijo permutacija
.
>>> slike({1: 3, 2: 4, 3: 2, 4: 1}, 1, 2)
[1, 3, 2]
def slike(permutacija, x, n): # Funkcijo definiramo rekurzivno. Če je n > 0, naredimo sliko y, nato # pa dodamo še seznam n - 1 slik elementa y. if n == 0: return [x] else: y = permutacija[x] ostale = slike(permutacija, y, n - 1) return [x] + ostale def slike_nerekurzivno(permutacija, x, n): r=[] for i in range(n+1): r.append(x) x = permutacija[x] return r
Sestavite funkcijo cikel(permutacija, x)
, ki vrne celoten cikel, ki
se začne s številom x
.
>>> cikel({1: 3, 2: 2, 3: 1}, 1)
[1, 3]
>>> cikel({1: 3, 2: 2, 3: 1}, 2)
[2]
def cikel(permutacija, x): # Dokler slika zadnjega elementa, ki smo ga dodali v cikel, ni enaka # začetnemu elementu y, dodamo sliko ter ponavljamo. cikel = [x] y = permutacija[x] while y != x: cikel.append(y) y = permutacija[y] return cikel
Sestavite funkcijo cikli(permutacija)
, ki vrne seznam disjunktnih
ciklov dane permutacije. Vsak cikel naj se začne z najmanjšim številom
v ciklu, cikli pa naj bodo urejeni po začetnem številu.
>>> cikli({1: 3, 2: 2, 3: 1})
[[1, 3], [2]]
def cikli(permutacija): # V seznam izracunaniCikli si shranjujemo do sedaj izračunane cikle, v seznam # ugotovljena pa vsa tista števila, za katera smo že ugotovili, kateremu # ciklu pripadajo. izracunaniCikli = [] ugotovljena = [] # Nato gremo zaporedoma čez vsa števila od 1 do n. Če za neko število # še nismo ugotovili, kam spada, je najmanjše v svojem ciklu. Zato # izračunamo njegov cikel, ga dodamo k ciklom, vsa števila iz cikla pa # dodamo med ugotovljena. for i in range(1, len(permutacija) + 1): if i not in ugotovljena: c = cikel(permutacija, i) izracunaniCikli.append(c) ugotovljena.extend(c) return izracunaniCikli
Socialno omrežje zaljubljenosti podamo s slovarjem, ki ime osebe preslika v množico vseh, v katere je oseba zaljubljena (ena oseba je lahko zaljubljena v več oseb). Na primer, slovar
s = {'Ana' : {'Bine','Cene'},
'Bine' : set(),
'Cene' : {'Bine'},
'Davorka' : {'Davorka'},
'Eva' : {'Bine'}}
nam pove, da je Ana zaljubljena v Bineta in Cenete, Bine ni zaljubljen, Cene ljubi Bineta, Davorka samo sebe in Eva Bineta.
Opomba*: Naloga je podobna nalogi"Ljubezen nam je vsem v pogubo", le da so tukaj ljubljene osebe v množici in ne v seznamu. Prav tako moramo vračati množice!_
Sestavite funkcijo narcisoidi(d)
, ki sprejme slovar zaljubljenih
in vrne monžico tistih, ki ljubijo same sebe.
def narcisoidi(d): return {oseba for oseba in d if oseba in d[oseba]}
Sestavite funkcijo ljubljeni(d)
, ki sprejme slovar zaljubljenih
in vrne množico tistih, ki so ljubljeni.
def ljubljeni(d): return {ljubljen for oseba in d for ljubljen in d[oseba]}
Sestavite funkcijo pari(d)
, ki sprejme slovar zaljubljenih
in vrne množico vseh parov, ki so srečno ljubljeni. Vsak
par naj se pojavi samo enkrat in sicer tako, da je sta zaljubljenca
našteta po abecedi. Na primer, če sta Ana in Bine zaljubljena,
dodamo par ('Ana','Bine')
.
def pari(d): return {tuple(sorted((x, y))) for x in d for y in d[x] if x in d[y]}
Sestavite funkcijo ustrezljivi(oseba, d)
, ki sprejme ime osebe ter
slovar zaljubljenih, vrne pa množico vseh ljudi, ki so do dane osebe
še posebej ustrežljivi. Posebej ustrežljivi so seveda za to, ker so
bodisi zaljubljeni v dano osebo, bodisi so zaljubljeni v osebo, ki je
posebej ustrežljiva do nje, in tako naprej.
Na primer, če imamo slovar
s = {'Ana' : {'Bine', 'Cene'},
'Bine' : {'Ana'},
'Cene' : {'Bine'},
'Davorka' : {'Davorka'},
'Eva' : {'Bine'}}
so do Ceneta posebej ustrežljivi Ana (ki je zaljubljena vanj), Bine (ki je zaljubljen v Ano), Eva (ki je zaljubljena v Bineta), ter seveda Cene, ki je zaljubljen v Evo.
def ustrezljivi(oseba, d): # seznam, v katerega nabiramo ustrežljive osebe ustrezljivi = set() # najprej dodamo tiste, ki ljubijo prvo osebo dodani = {o for o in d if oseba in d[o]} # dokler smo koga dodali, dodajamo ustrežljive while dodani: ustrezljivi.update(dodani) # sedaj pa dodajamo tiste, ki ljubijo nazadnje dodane osebe dodani = {o for o in d for dodan in dodani if dodan in d[o] and o not in ustrezljivi} return ustrezljivi
V neki datoteki, ki ima lahko več vrstic, so zapisana imena. Znotraj posamične vrstice so imena ločena z vejicami (brez presledkov). Primer take datoteke:
Jaka,Peter,Miha,Peter,Anja
Franci,Roman,Renata,Jožefa
Pavle,Tadeja,Arif,Filip,Gašper
Sestavite funkcijo kolikokrat_se_pojavi(niz, ime)
, ki vrne število
pojavitev imena ime
v nizu imen niz
.
>>> kolikokrat_se_pojavi('Alojz,Samo,Peter,Alojz,Franci', 'Alojz')
2
def kolikokrat_se_pojavi(niz, ime): return niz.split(',').count(ime) # Alternativna rešitev (brez uporabe metode count) def kolikokrat_se_pojavi_alt(niz, ime): vsa_imena = niz.split(',') stevec = 0 for s in vsa_imena: if s == ime: stevec += 1 return stevec
Sestavite funkcijo koliko(niz, datoteka)
, ki na izhodno datoteko z
imenom datoteka
za vsako ime zapiše, kolikokrat se pojavi v nizu niz
.
Na primer, če je niz enak 'Jaka,Luka,Ante,Luka'
, naj funkcija v izhodno
datoteko zapiše
Jaka 1
Luka 2
Ante 1
Pozor: Imena naj bodo izpisana v takem vrstnem redu, kakor si sledijo
njihove prve pojavitve v nizu niz
.
def koliko(niz, datoteka): imena = niz.split(',') brez_ponovitev = [] for ime in imena: if ime not in brez_ponovitev: brez_ponovitev.append(ime) with open(datoteka, 'w', encoding='utf-8') as f: for ime in brez_ponovitev: print(ime, imena.count(ime), file=f) # Alternativna rešitev def koliko_alt(niz, datoteka): imena = [] stevci = [] for ime in niz.split(','): if ime not in imena: imena.append(ime) stevci.append(1) else: stevci[imena.index(ime)] += 1 with open(datoteka, 'w', encoding='utf-8') as f: for ime, stevec in zip(imena, stevci): print(ime, stevec, file=f) # Še ena možna rešitev (z uporabo slovarja) def koliko_alt2(niz, datoteka): imena = niz.split(',') stevec = {} for ime in imena: stevec[ime] = stevec.get(ime, 0) + 1 with open(datoteka, 'w', encoding='utf-8') as f: for ime in imena: if ime not in stevec: continue print(ime, stevec[ime], file=f) del stevec[ime]
Sestavite funkcijo koliko_iz_datoteke(vhodna, izhodna)
, ki naj naredi
isto kot funkcija koliko
, le da podatke prebere iz datoteke. Torej, na
izhodno datoteko z imenom izhodna
naj za vsako ime zapiše, kolikokrat
se pojavi v datoteki z imenom vhodna
.
Pozor: Vhodna datoteka ima lahko več vrstic. Imena izpišite v enakem
vrstnem redu, kot si sledijo njihove prve pojavitve v datoteki vhodna
.
def koliko_iz_datoteke(vhodna, izhodna): vrstice = [] # Seznam vseh vrstic v datoteki vhodna. with open(vhodna, encoding='utf-8') as f: for vrstica in f: vrstice.append(vrstica.strip()) # Odstranimo '\n' s konca vrstice. imena = ','.join(vrstice) # Niz z vsemi imeni iz datoteke. koliko(imena, izhodna)
Sestavite funkcijo koliko_urejen(vhodna, izhodna)
, ki na izhodno
datoteko z imenom izhodna
za vsako ime zapiše, kolikokrat se pojavi v
datoteki z imenom vhodna
. Imena naj bodo urejena padajoče po frekvenci
pojavitev. Imena, ki imajo enako frekvenco, naj bodo nadalje urejena
leksikografsko (tj. po abecednem vrstnem redu).
Primer: Če je na datoteki imena_vhod.txt vsebina
Luka,Jaka
Luka,Miha,Miha
Miha,Aleš,Aleš
naj bo po klicu funkcije koliko_urejen('imena_vhod.txt', 'imena_izhod.txt')
na datoteki imena_izhod.txt naslednja vsebina:
Miha 3
Aleš 2
Luka 2
Jaka 1
def koliko_urejen(vhod, izhod): imena = [] # Seznam vseh imen. brez_ponovitev = [] # Seznam imen brez ponovitev. with open(vhod, encoding='utf-8') as f: for vrstica in f: for ime in vrstica.strip().split(','): imena.append(ime) if ime not in brez_ponovitev: brez_ponovitev.append(ime) # Seznam pari bo vseboval pare oblike (-3, 'Miha'). Druga komponenta bo # ime; prva komponenta bo število pojavitev tega imena, pomnoženo z -1. pari = [] for ime in brez_ponovitev: pari.append((-imena.count(ime), ime)) # Metoda sort uredi števila naraščajoče po vrednosti, nize pa leksikografsko # (tj. tako kot so urejeni v leksikonu). Pare uredi glede na prvo komponento, # tiste z enako prvo komponento pa še glede na drugo komponento. pari.sort() with open(izhod, 'w', encoding='utf-8') as f: for s, ime in pari: print(ime, -s, file=f) # Alternativna rešitev (uporablja izpeljane sezname, množice in lambda funkcije) def koliko_urejen_alt(vhod, izhod): with open(vhod, encoding='utf-8') as f: imena = ','.join([vrstica.strip() for vrstica in f]) enkrat_imena = set(imena.split(',')) pari = [(ime, kolikokrat_se_pojavi(imena, ime)) for ime in enkrat_imena] pari.sort(key=lambda p: (-p[1], p[0])) with open(izhod, 'w', encoding='utf-8') as f: for ime, s in pari: print(ime, s, file=f)
Vsako LEGO kocko lahko opišemo z dvema lastnostima: tipom (torej obliko) in barvo.
Če boste nalogo uspešno rešili še pred koncem, si lahko ogledate
seznam vseh možnih barv
kock, pri tej nalogi pa bomo predpostavili le tri barve: rdečo, modro
in rumeno. Tipov LEGO kock pa je ogromno,
zato jih bomo predstavili kar z nizi kot na primer '2x2'
, '4x1-tanka'
ali pa 'nogice'
. Sprejmimo dogovor, da nobeno ime tipa ne vsebuje pike.
Vsebino škatle podamo s seznamom vseh kock, ki so v njej. Vsaka kocka
je opisana z nizom, ki vsebuje tip kocke in barvo, ki sta ločeni s piko.
Npr. kocka tipa '2x2'
rdeče barve je predstavljena z nizom '2x2.rdeča'
.
Napišite funkcijo slovar_kock(skatla)
, ki dobi seznam skatla
in sestavi
slovar vsebovanih kock, urejen po tipih ter po barvah, kot prikazuje primer:
>>> slovar_kock(['2x2.rdeča', '2x2.rdeča', 'nogice.modra', '2x2.modra'])
{'nogice': {'modra': 1}, '2x2': {'rdeča': 2, 'modra': 1}}
def slovar_kock(skatla): '''Vrne slovar lego kock''' sk = dict() for kocka in skatla: tip, barva = kocka.split('.') if tip not in sk: sk[tip] = dict() sk[tip][barva] = sk[tip].get(barva, 0) + 1 return sk
Napišite funkcijo lahko_sestavimo(skatla, model)
, ki dobi dva slovarja
kock, in vrne True
natanko tedaj, ko je možno modelček (za katerega
potrebujemo kocke, ki so podane s slovarjem model
) sestaviti s kockami,
ki so v škatli.
>>> model = {'4x1': {'modra': 1}, '2x2': {'rdeča': 2, 'modra': 1}}
>>> skatla = {'4x1': {'modra': 3, 'rdeča': 2}, '2x2': {'rdeča': 4, 'modra': 1, 'rumena': 5}}
>>> lahko_sestavimo(skatla, model)
True
>>> model_2 = {'4x1': {'rumena': 1}, '2x2': {'rdeča': 1, 'rumena': 2}}
>>> lahko_sestavimo(skatla, model_2)
False
def lahko_sestavimo(skatla, model): '''Ali lahko sestavimo model, če imamo na voljo škatlo kock skatla''' for tip, barve in model.items(): for barva, cnt in barve.items(): if cnt > skatla.get(tip, {}).get(barva, 0): return False return True
Napišite funkcijo hitro_sestavljanje(skatla, model)
, ki vrne True
,
če je možno modelček sestaviti “na hitro”, torej tako, da barve niso
pomembne (še vedno pa je pomembno, da uporabimo kocke ustreznega tipa).
>>> model = {'4x1': {'modra': 2}, '2x2': {'rdeča': 2, 'modra': 1}}
>>> skatla_1 = {'4x1': {'rdeča': 3}, '2x2': {'rdeča': 1, 'rumena': 5}}
>>> skatla_2 = {'4x1': {'rumena': 3, 'rdeča': 2}, '2x2': {'rumena': 1, 'rdeča': 1}}
>>> hitro_sestavljanje(skatla_1, model)
True
>>> hitro_sestavljanje(skatla_2, model)
False
def hitro_sestavljanje(skatla, model): '''Ali lahko "na hitro"(brez upoštevanja barv) sestavimo model iz kock v škatli skatla ''' for tip, barve in model.items(): if sum(barve.values()) > sum(skatla.get(tip, {}).values()): return False return True
Sestavite funkcijo vsota_potenc(k, n)
, ki vrne vsoto
>>> vsota_potenc(10, 2)
1025
Ali znaš napisati rešitev, kjer funkcija vsebuje en sam stavek oblike return nekIzraz
def vsota_potenc(k, n): '''Vrne vsoto potenc''' vsota = 0 for i in range(1, n+1): # preko vseh členov člen = i**k # trenutni člen vsota += člen return vsota def vsota_potencV2(k, n): '''Vrne vsoto potenc s pomočjo izpeljanih seznamov''' return sum([i**k for i in range(1, n+1)])
Sestavite funkcijo inverzna_harmonicna(x)
, ki pove, koliko členov
harmonične vrste
>>> inverzna_harmonicna(2)
4
Ali bi pri tej nalogi šlo z izpeljanim seznamom?
def inverzna_harmonicna(x): '''Koliko členov harmonične vrste moramo sešteti, da presežemo x''' trenutnaVsota = 0 k = 1 # števec členov (enak imenovalcu) while trenutnaVsota <= x: # nismo še preko vsote trenutnaVsota += 1 / k k += 1 return k - 1 # ker smo začeli šteti z 1 pred zanko
Sestavite funkcijo vsota_stevk(n)
, ki vrne vsoto števk danega pozitivnega celega števila.
Zgled:
>>> vsota_stevk(2014)
7
Če celo število ni pozitivno, vrnemo 0. Ali znaš nalogo rešiti z izpeljanim seznamom, s pomočjo enega samega stavka return?
def vsota_stevk(n): '''Vrne vsoto števk pozitivnega celega števila''' return sum([int(stevka) for stevka in str(n)]) if n > 0 else 0
Sestavite funkcijo vsote(n)
, ki izračuna, na koliko načinov lahko
zapišemo naravno število n
kot vsoto naraščajočega zaporedja naravnih
števil. Na primer, klic vsote(7)
vrne 5
, ker lahko 7 zapišemo na
naslednje načine:
7 = 7
7 = 1 + 6
7 = 2 + 5
7 = 3 + 4
7 = 1 + 2 + 4
Opomba: Ta naloge je malce težja od ostalih iz tega sklopa.
def stej(m, j): """ Pomožna funkcija, ki šteje vsote števila m, pri čemer mora biti prvi člen v vsoti večji ali enak številu j. """ if m == 0: return 1 elif j > m: return 0 else: return sum([stej(m-i, i+1) for i in range(j, m+1)]) def vsote(n): return stej(n, 1)
V seznamu imamo podatke o prilivih in odlivih s tekočega računa. Pozitivna števila predstavljajo priliv (polog denarja), negativna pa dvig. Vsak element seznama predstavlja en dan. Če na nek dan ni prilivov ali dvigov, je vrednost v seznamu 0. Privzemite, da je na začetku stanje na računu 0.
Sestavite funkcijo koncno_stanje(spremembe)
, ki iz danega seznama
prilivov in odlivov izračuna končno stanje.
Pri rešitvi ne uporabi zanke neposredno v kodi te funkcije.
def koncno_stanje(spremembe): '''Izračuna končno stanje na računu''' return sum(spremembe)
Sestavite funkcijo stanja(spremembe)
, ki iz danega seznama
prilivov in odlivov ustvari seznam vmesnih stanj na računu.
Privzemite, da je na začetku stanje na računu 0. To naj bo prva "sprememba" v seznamu
>>>stanja([10, -5, 20, -6])
[0, 10, 5, 25, 19]
Ali znaš nalogo rešiti tako, da vsebuje le stavek oblike return <nekIzraz>
?
def stanja(spremembe): '''Vrne seznam vmesnih stanj na računu''' trenutnoStanje = 0 stanja = [0] for sprememba in spremembe: # pregledamo vse transkacije v seznamu trenutnoStanje += sprememba stanja.append(trenutnoStanje) return stanja def stanjaV2(spremembe): '''Vrne seznam vmesnih stanj na računu''' # nalogo lahko rešimo s pomočjo izpeljanih seznamov # na vsakem seznamu generiramo ustrezni začetni del seznama in ga seštejemo return [sum(spremembe[:i]) for i in range(len(spremembe)+1)]
Sestavite funkcijo ekstrema(spremembe)
, ki pri danih spremembah
stanja poišče vrednosti, ko je bilo stanje na računu najnižje oziroma
najvišje. Pri tem seveda zanemari začetno stanje 0 in prepostavi, da je prišlo do
vsaj ene spremembe
Stanji naj vrne v obliki nabora.
>>>ekstrema([10, -5, 20, -6])
(5, 25)
Rešitev poišči brez uporabe zank neposredno v kodi te funkcije.
def ekstrema(spremembe): '''Vrne najnižje in najvišje stanje''' s = stanja(spremembe)[1:] # uporabimo funkcijo prejšnje naloge, a začetno stanje (0) zavržemo najnizje = min(s) najvisje = max(s) return (najnizje, najvisje)
Sestavite funkcijo kdaj_ekstrema(spremembe)
, ki pri danih spremembah
stanja poišče število dni od začetka, ko je bilo stanje na računu najnižje oziroma
najvišje. Rezultat naj vrne v obliki nabora.
>>>kdaj_ekstrema([10, -5, 20, -6])
(2, 3)
Rešitev poišči brez uporabe zank neposredno v kodi te funkcije.
def kdaj_ekstrema(spremembe): '''Vrne število dni od začetka, ko smo dosegli najnižje in najvišje stanje''' s = stanja(spremembe) [1:] # uporabimo funkcijo prejšnje naloge, a začetno stanje (0) zavržemo najnizje = s.index(min(s)) + 1 najvisje = s.index(max(s)) + 1 return (najnizje, najvisje)
Sestavite funkcijo razlika(spremembe, i, j)
, ki poišče razliko
stanj med dnevoma z indeksom i
in j
. Na dan 0 je bilo seveda stanje 0.
>>>razlika([10, -5, 20, -6], 1, 3)
15
>>>razlika([10, -5, 20, -6], 1, 2)
-5
Predpostavite lahko, da je i
manjši ali enak j
.
Rešitev poišči brez uporabe zank neposredno v kodi te funkcije.
def razlika(spremembe,i,j): '''Vrne spremembo med dnevoma i in j''' return sum(spremembe[i:j])
Sestavite funkcijo najvecja_razlika(spremembe)
, ki poišče največji
relativni priliv. Z drugimi besedami, poišče največjo vrednost, ki jo
zavzame vsota poljubnega strnjenega podseznama.
Tako na primer najvecja_razlika([10, -13, 3, 20, -2, 5])
vrne
3 + 20 - 2 + 5 = 26.
Če je seznam spremembe
prazen, naj funkcija vrne None
.
def najvecja_razlika(spremembe): '''Izračuna največji relativni priliv v nekem obdobju''' if spremembe == []: return None # ni bilo nobenih sprememb n = len(spremembe) najRaz = spremembe[0] # načeloma je kandidat kar dogajanje prvi dan for začetek in range(0, n): for konec in range(začetek, n): # vsi možni začeteki in konci podseznamov vsotaPodsez = 0 for indeks in range(začetek, konec+1): # izračunamo vsoto podseznama vsotaPodsez += spremembe[indeks] if vsotaPodsez > najRaz: # našli smo večji priliv najRaz = vsotaPodsez return najRaz
Sestavite funkcijo najvecja_razlikaV2(spremembe)
, ki poišče največji
relativni priliv. Z drugimi besedami, poišče največjo vrednost, ki jo
zavzame vsota poljubnega strnjenega podseznama.
Tako na primer najvecja_razlikaV2([10, -13, 3, 20, -2, 5])
vrne
3 + 20 - 2 + 5 = 26.
Če je seznam spremembe
prazen, naj funkcija vrne None
.
Uporabi izpeljanje sezname!
def najvecja_razlikaV2(spremembe): '''Izračuna največji relativni priliv v nekem obdobju''' if spremembe == []: return None # ni bilo nobenih sprememb n = len(spremembe) return max(sum(spremembe[i:j+1]) for i in range(0, n) for j in range(i, n)) # generiramo vse možne podsezname, jih seštejemo # in med vsotami poiščemo največjo
Pravimo, da je sprehod po točkah v ravnini cik-cakast, če gremo iz
točke
Sestavite funkcijo je_cikcakast(sprehod)
, ki vrne True
natanko tedaj,
kadar je sprehod, podan z zaporedjem točk sprehod
, cik-cakast. Zgled:
>>> je_cikcakast([(1, 1), (2, 0), (3, -1), (4, 0), (5, 1)])
True
def je_cikcakast(sprehod): '''Ali je sprehod, podan kot seznam parov koordinat, cik cakast''' for i in range(len(sprehod) - 1): # jemali bomo po dve točki - začetek in konec, zato končamo pri predzadnji točki (x1, y1), (x2, y2) = sprehod[i], sprehod[i + 1] # razpakiranje podatkov if x2 != x1 + 1 or abs(y2 - y1) != 1: return False # že en ne cikcakast premik pove rezultat return True # vsi premiki so bili cikcak
Sestavite funkcijo prestavi_v_1kvadrant(sprehod)
, ki sprehod zamakne
tako, da v celoti poteka izključno v 1. kvadrantu ter da je njegova prva
točka na ordinatni, njegova najnižja točka pa na abscisni osi. Zgled:
>>> prestavi_v_1kvadrant([(1, 1), (2, 0), (3, -1), (4, 0), (5, 1)])
[(0, 2), (1, 1), (2, 0), (3, 1), (4, 2)]
def prestavi_v_1kvadrant(sprehod): '''Prestavi sprehod, podan kot seznam parov koordinat, v 1kvadrant''' # poiščemo minimalno x in min. y koordinato min_x, min_y = sprehod[0] for tockaX, tockaY in sprehod: min_x = min(min_x, tockaX) # manjši od obeh je kandidat za min min_y = min(min_y, tockaY) novSprehod = [] for x, y in sprehod: #premaknemo za ustrezna minimuma novSprehod += [(x - min_x, y - min_y)] return novSprehod def prestavi_v_1kvadrant_V2(sprehod): '''Prestavi sprehod, podan kot seznam parov koordinat, v 1kvadrant''' # s pomočjo izpeljanih seznamov min_x = min(x for x, _ in sprehod) min_y = min(y for _, y in sprehod) return [(x - min_x, y - min_y) for x, y in sprehod]
Sestavite funkcijo stevilo_cikcakastih(zac, kon)
, ki vrne število
vseh cik-cakastih sprehodov med točkama zac
in kon
. Zgled:
>>> stevilo_cikcakastih((0, 0), (9, 3))
84
>>> stevilo_cikcakastih((0, 0), (0, 0))
1
>>> stevilo_cikcakastih((0, 0), (-1, 0))
0
>>> stevilo_cikcakastih((1, 1), (9, 3))
56
>>> stevilo_cikcakastih((1, -1), (9, 3))
28
Namig: Kam gre lahko prvi korak cik-cakastega sprehoda? Dobro si oglejte zgornji zgled.
def stevilo_cikcakastih(zac, kon): '''Koliko cikcakastih sprehodov je med začetno in končno točko''' (xz, yz), (xk, yk) = zac, kon if zac == kon: return 1 elif xz >= xk or abs(yz - yk) > xk - xz: return 0 else: # gremo lahko gor ali dol return stevilo_cikcakastih((xz + 1, yz + 1), kon) + stevilo_cikcakastih((xz + 1, yz - 1), kon)
Sestavite funkcijo narisi_sprehod(sprehod, izhod)
, ki v datoteko z
imenom izhod
z znaki /
in \
izpiše cik-cakast sprehod, podan z
množico točk sprehod
. Sprehod naj premakne tako, da bo
najbolj levi znak v prvem stolpcu, najvišji pa v prvi
vrstici datoteke.
Sprehod
[(0, 0), (1, 1), (2, 0), (3, -1), (4, -2), (5, -1)]
morate tako izpisati kot:
/\
\
\/
Enako sliko da npr. tudi
[(1, 1), (2, 2), (3, 1), (4, 0), (5, -1), (6, 0)]
sprehod
[(5, -4), (6, -3), (7, -4), (8, -5), (9, -4), (10, -3), (11, -4), (12, -5)]
pa kot:
/\ /\
\/ \
Testni primeri delovanje primerjajo na sledečih cik-cakastih sprehodih:
[(0, 0), (1, 1), (2, 2), (3, 3), (4, 4), (5, 5)]
,[(0, 0), (1, -1), (2, -2), (3, -3), (4, -4), (5, -5)]
,[(0, 0), (1, 1), (2, 0), (3, -1), (4, -2), (5, -1)]
[(1, 1), (2, 2), (3, 1), (4, 0), (5, -1), (6, 0)]
[(5, -4), (6, -3), (7, -4), (8, -5), (9, -4), (10, -3), (11, -4), (12, -5)]
Namig:
def narisi_sprehod(sprehod, izhod): '''Na izhodno datoteko nariše sprehod''' sprehod = prestavi_v_1kvadrant(sprehod) # prestavimo vse skupaj v prvi kvadrant # poiščemo maksimalno x in max. y koordinato (velikost "slike") max_x, max_y = sprehod[0] for tockaX, tockaY in sprehod: max_x = max(max_x, tockaX) # manjši od obeh je kandidat za min max_y = max(max_y, tockaY) # izhodna slika je najprej ustrezna matrika (seznam seznamov), sestavljena iz presledkov izhSlika = [] for vr in range(max_y): vrstica = [' '] * (max_x + 1) izhSlika += [vrstica] for i in range(len(sprehod) - 1): (x1, y1), (x2, y2) = sprehod[i], sprehod[i + 1] if y2 - y1 == 1: izhSlika[max_y - y2][x1] = '/' elif y2 - y1 == -1: izhSlika[max_y - y1][x1] = '\\' with open(izhod, 'w') as f: for vrstica in izhSlika: izpVrstica = ''.join(vrstica) # združimo (zlepimo) vse znake v vrstici print(izpVrstica, file=f) def narisi_sprehodV2(sprehod, izhod): '''Na izhodno datoteko nariše sprehod''' # uporaba izpeljanih seznamov sprehod = prestavi_v_1kvadrant(sprehod) # prestavimo vse skupaj v prvi kvadrant # poiščemo minimalno x in min. y koordinato max_x, max_y = max(x for x, _ in sprehod), max(y for _, y in sprehod) # izhodna slika je najprej ustrezna matrika (seznam seznamov), sestavljena iz presledkov izhSlika = [[' ' for i in range(max_x + 1)] for j in range(max_y)] for i in range(len(sprehod) - 1): (x1, y1), (x2, y2) = sprehod[i], sprehod[i + 1] if y2 - y1 == 1: izhSlika[max_y - y2][x1] = '/' elif y2 - y1 == -1: izhSlika[max_y - y1][x1] = '\\' with open(izhod, 'w') as f: for vrstica in izhSlika: print(''.join(vrstica), file=f)
Na izlet v Hrčkovo deželo se je odpravilo nekaj družin. Seznam udeležencev izleta je podan v obliki seznama nizov priimkov in imen, ločenih z vejicami. Seveda ima lahko neka oseba več imen ali več priimkov, drugih znakov v imenih (npr. vezaj) pa ni. Primer seznama:
udelezenci = ['Novak, Janez Peter', 'Novak, Ana', 'Kovač Novak, Meta', 'Kovač, Petra']
Sestavi funkcijo vrniImePriimek(oseba)
, ki za dani niz oseba
vrne par
(ime, priimek)
Primeri:
>>> vrniImePriimek('Novak, Janez')
('Janez', 'Novak')
>>> vrniImePriimek('Kovač Novak, Matej')
('Matej', 'Kovač Novak')
>>> vrniImePriimek('Gott Hell, Ana Jana')
('Ana Jana', 'Gott Hell')
def vrniImePriimek(niz): '''Niz razbijemo na ime in priimek - ločilo je vejica''' s = niz.split(',') return (s[1].strip(), s[0].strip())
Družine bi se rade posedle za mize tako, da bodo ob isti mizi sedeli
člani iste družine. Napišite funkcijo razpored_po_mizah(udelezenci)
, ki
naredi slovar, katerega ključi so priimki, vrednosti pa množice imen oseb
iste družine. (Osebi sta člana iste družine, ko imata povsem enaka priimka.)
Primer:
>>> razpored_po_mizah(['Novak, Janez', 'Kovač, Franc', 'Kovač, Jožefa', 'Novak, Micka', 'Kovač Novak, Matej'])
{'Novak': {'Janez', 'Micka'}, 'Kovač Novak': {'Matej'}, 'Kovač': {'Franc', 'Jožefa'}}
def razpored_po_mizah(udelezenci): '''Vrne slovar z razporeditvijo po mizah''' mize = dict() for oseba in udelezenci: (ime, priimek) = vrniImePriimek(oseba) osebe = mize.get(priimek, set()) # iz slovarja dobimo množico oseb, ki že sedijo za mizo oz. prazno množico osebe.add(ime) # dodamo osebo k mizi mize[priimek] = osebe # sedaj pri družini priimek sede te osebe return mize
Organizator izleta se je odločil, da bo poiskal najbolj popularno ime.
Če ima neka oseba več imen (npr. 'Kovač, Ana Beti'
), štejemo vsako
komponento posebej. Napišite funkcijo popularno_ime(udelezenci)
, ki
vrne seznam najbolj popularnih imen, urejenih po abecedi. (Seznam ima
več elementov le v primeru, ko je na vrhu popularnosti več imen.)
Primer:
>>> popularno_ime(['Horvat, Ivan Jožef', 'Hočevar, Franc', 'Horvat, Franc', 'Novak, Jožef', 'Novak, Mici'])
['Franc', 'Jožef']
def popularno_ime(udelezenci): '''Vrne seznam najbolj popularnih imen''' števciImena = dict() for oseba in udelezenci: (ime, priimek) = vrniImePriimek(oseba) komponente = ime.split() # ime razbijemo na dele for k in komponente: # povečamo števce vseh imen števciImena[k] = števciImena.get(k, 0) + 1 najPogostost = max(števciImena.values()) # kateri števec je največji # seznam imen s to največjo pogostostjo kateraImena = [] for ime, frekvenca in števciImena.items(): if frekvenca == najPogostost: kateraImena.append(ime) kateraImena.sort() # seznam imen mora biti urejen po abecedi return kateraImena def popularno_imeV2(udelezenci): '''Vrne seznam najbolj popularnih imen''' # uporaba izpeljanih seznamov števciImena = dict() for oseba in udelezenci: (ime, priimek) = vrniImePriimek(oseba) komponente = ime.split() # ime razbijemo na dele for k in komponente: # povečamo števce vseh imen števciImena[k] = števciImena.get(k, 0) + 1 m = max(števciImena.values()) # kateri števec je največji kateraImena = [ime for ime, frekvenca in števciImena.items() if frekvenca == m] # seznam imen s to pogostostjo kateraImena.sort() # seznam imen mora biti urejen po abecedi return kateraImena
Napišite funkcijo morda_sorodnika(prva_oseba, druga_oseba)
, ki za dve
osebi, podani z nizoma oblike 'priimki, imena'
, vrne True
, če se ujemata
v vsaj enem od priimkov (in False
sicer). Primer:
>>>> morda_sorodnika('Kovač Novak, Ana', 'Novak, Anja')
True
>>>> morda_sorodnika('Kovač Novak, Ana', 'Novak Novak, Anja')
True
>>>> morda_sorodnika('Kovač, Ana', 'Novak, Ana')
False
def morda_sorodnika(prva_oseba, druga_oseba): '''Sta osebi morda sorodnika''' _, priimek_p = vrniImePriimek(prva_oseba) # imena sploh ne potrebujemo, zato _ _, priimek_d = vrniImePriimek(druga_oseba) priimki_d = priimek_d.split() # vsi deli priimka for priimek in priimek_p.split(): if priimek in priimki_d: # našli smo ujemanje v delu return True return False
Napišite funkcijo rodbina(oseba, udelezenci)
, ki vrne seznam oseb (skupaj
z osebo oseba
), ki so morda sorodniki dane osebe, ali pa morda sorodniki
morebitnih sorodnikov dane oseba ali pa morda sorodniki morebitnih sorodnikov
morebitnih sorodnikov danes osebe itn. Seznam naj bo urejen po abecedi.
Primer:
>>> udelezenci = ['A, a', 'A B, b', 'C D, c', 'C A, c', 'Y, x']
>>> rodbina('A, x', udelezenci)
['A, x', 'A, a', 'A B, b', 'C A, c', 'C D, c']
def rodbina_rek(nasi, vasi): '''Vrne seznam tistih iz seznama vasi, ki so morda sorodniki tistih iz nasi''' novi = [] # katere osebe bomo dodali na novo ostanek = [] # kateri del seznama vasi moramo še pregledati (kateri ne bodo neosredno sorodniki tistih iz nasi) for v in vasi: # pregledamo vse kandidate za sorodnike for n in nasi: # je v morda sorodnik komu iz nasi if morda_sorodnika(n, v): # če je, v dodamo med nove in gremo na naslednjega kandidata v vasi novi += [v] break else: # če v ni sorodnik nikomur (for se je izvedel do konca), ga bomo pogledali ali je sorodnik sorodnikov ostanek += [v] # ti bodo morda sorodniki sorodnikov ... if novi == []: # če v tem pregledu nismo dodali nikogra, so vsi sordniki že v nasi return nasi else: return rodbina_rek(nasi + novi, ostanek) # dodamo nove in zaradi tega pregledamo, če so v ostanek sorodniki teh dodanih def rodbina(oseba, udelezenci): '''Vrne seznam oseb (skupaj z osebo oseba), ki so morda sorodniki dane osebe, ali pa morda sorodniki morebitnih sorodnikov ... dane oseba''' return sorted(rodbina_rek([oseba], udelezenci))
Slovar lahko v Pythonu predstavimo s slovarjem – presenetljivo, kajne? Natančneje, ključi v slovarju so besede, pripadajoče vrednosti pa so množice vseh možnih prevodov. Na primer:
{'je': {'is', 'eats'}, 'kosilo': {'lunch'},
'mama': {'mother', 'mum', 'mummy'}}
Sestavite funkcijo obratni(slov)
, ki vrne obratni slovar danega
slovarja slov
.
>>> obratni({'je': {'is', 'eats'}, 'žre': {'bugs', 'eats'}})
{'bugs': {'žre'}, 'eats': {'je', 'žre'}, 'is': {'je'}}
def obratni(slov): '''Vrne obratni slovar''' obrat = {} for beseda, prevodi in slov.items(): for prevod in prevodi: besedePrevoda = obrat.get(prevod, set()) # obstoječi prevodi ali nova množica besedePrevoda.add(beseda) obrat[prevod] = besedePrevoda # popraviomo ali na novo postavimo eleemnt v slovar return obrat
Sestavite funkcijo nedvoumne_in_dvoumne(slov)
, ki vrne par dveh množic:
v prvi naj bodo vse besede iz slovarja slov
, ki imajo natanko en možen
prevod, v drugi pa vse tiste, ki jih imajo več.
>>> nedvoumne_in_dvoumne({'je': {'is', 'eats'}, 'kosilo': {'lunch'}, 'solata': {'salad'}}
({'kosilo', 'solata'}, {'je'})
def nedvoumne_in_dvoumne(slov): '''Vrne dv množici - prvo besede z enim prevodom in drugo vse ostale ''' nedvoum, dvoum = set(), set() for beseda, prevodi in slov.items(): if len(prevodi) == 1: nedvoum.add(beseda) else: dvoum.add(beseda) return nedvoum, dvoum
Sestavite funkcijo vsi_mozni_prevodi(slov, stav)
, ki vrne množico
vseh možnih “prevodov” danega stavka stav
glede na dani slovar slov
.
Stavek je niz, sestavljen iz besed, ločenih s presledki. Če besede ni v
slovarju, naj v prevodu ostane taka, kakršna je.
Namig: sestavite še pomožno funkcijo, ki namesto niza stav
sprejme
seznam besed.
def prevodi_pomozna(slov, besede): '''Vrne seznam, kjer so elementi seznami besed, ki predstavljajo možen prevod''' if len(besede) == 0: return [[]] else: vsi_prevodi = [] prevodi = slov.get(besede[0], {besede[0]}) prevodi_preostanka = prevodi_pomozna(slov, besede[1:]) for prevod in prevodi: for prevod_preostanka in prevodi_preostanka: vsi_prevodi.append([prevod] + prevod_preostanka) return vsi_prevodi def vsi_mozni_prevodi(slov, stav): '''Vrne seznam vse možnih prevodov''' besede = stav.split(' ') # razdelimo stavek na besede prevodi = prevodi_pomozna(slov, besede) #Seznam prevodov množicaPrevodov = set() for enPrevodSeznam in prevodi: enPrevod = ' '.join(enPrevodSeznam) # besede združimo s presledki množicaPrevodov.add(enPrevod) return množicaPrevodov
Sestavite funkcijo preberi(vhod)
, ki prebere datoteko z imenom vhod
in vrne slovar, zapisan v njej. Slovar je v datoteki predstavljen tako,
da je vsaka beseda v svoji vrstici, pod njo pa so v vrsticah, ki se
začnejo z znakom -
, zapisani njeni prevodi. Na primer, v datoteki
je
- is
- eats
kosilo
- lunch
mama
- mother
- mum
- mummy
je zapisan ravno slovar
{'je': {'is', 'eats'}, 'kosilo': {'lunch'},
'mama': {'mother', 'mum', 'mummy'}}
Predpostavite lahko, da je vhodna datoteka vedno zgornje oblike.
def preberi(vhod): '''Iz datoteke sestavi slovar prevodov''' slov = {} for line in open(vhod): if line[0] == '-': # gre za prevod slov[beseda].add(line[2:].strip()) # znebimo se še - in presledka else: beseda = line.strip() # nopva beseda, ki so prevajamo slov[beseda] = set() return slov
Primož rad bere knjige. Doma ima polne police samih dobrih strokovnih
in leposlovnih knjig. Prijatelji si pri njem pogosto sposojajo knjige.
Primož za vsako knjigo vodi evidenco o tem, komu jo je posodil. Podatke
hrani v slovarju, kjer so ključi oznake knjig (nizi), vrednosti pa so
seznami imen prijateljev (prav tako nizi), ki so si sposodili to knjigo,
v kronološkem vrstnem redu. Tisti, ki ima knjigo trenutno pri sebi, je
na zadnjem mestu v seznamu. Če ima Primož knjigo trenutno doma, potem
je na zadnjem mestu v slovarju vrednost None
. Primer:
evidenca_1 = {
'hpotter1': ['Cilka', 'Bojan', 'Samo'],
'hpotter2': ['Bojan', 'Cilka', None],
'agot': ['Cilka', 'Špela', 'Bojan'],
'acok': ['Samo', None],
'vrabec90': ['Klemen', 'Bojan'],
'vidav10': [None]
}
Napišite funkcijo imam_doma(evidenca)
, ki sprejme slovar, kot je
opisan zgoraj, in vrne množico vseh knjig, ki jih ima Primož v tem
trenutku doma. Zgled:
>>> imam_doma(evidenca_1)
{'hpotter2', 'acok', 'vidav10'}
def imam_doma(evidenca): doma = set() for k, v in evidenca.items(): if v[-1] is None: doma.add(k) return doma
Primož bi rad poznal za vsakega prijatelja množico knjig, ki jih ima
ta prijatelj trenutno izposojene. Napišite funkcijo kdo_kaj(evidenca)
,
ki sprejme slovar, kot je opisan zgoraj, in vrne slovar, kjer so ključi
imena prijateljev, vrednosti pa množice knjig, ki jih imajo ti v tem
trenutku sposojene. Zgled:
>>> kdo_kaj(evidenca_1)
{'Samo': {'hpotter1'}, 'Bojan': {'agot', 'vrabec90'}}
def kdo_kaj(evidenca): trenutno = {} for k, v in evidenca.items(): kdo = v[-1] if kdo is None: continue if kdo not in trenutno: trenutno[kdo] = set() trenutno[kdo].add(k) return trenutno
Primoža zanima, kaj njegovi prijatelji radi berejo. Sestavite funkcijo
zgodovina(evidenca, ime)
, ki sprejme slovar, kot je opisan zgoraj, in
ime enega od prijateljev. Funkcija naj vrne množico vseh knjig, ki jih
je imel prijatelj z imenom ime
kadarkoli izposojene. Zgled:
>>> zgodovina(evidenca_1, 'Bojan')
{'hpotter2', 'hpotter1', 'agot', 'vrabec90'}
def zgodovina(evidenca, ime): malha = set() for k, v in evidenca.items(): if ime in v: malha.add(k) return malha
Primoža zanima, kako strastni bralci so njegovi prijatelji. Napišite
funkcijo statistika(evidenca)
, ki sprejme slovar, kot je opisan zgoraj
in vrne nov slovar, kjer so ključi imena vseh prijateljev, ki so si pri
Primožu kadarkoli izposodili kakšno knjigo, vrednost vsakega ključa pa
je število različnih knjig, ki si jih je izposodil ta prijatelj. Zgled:
>>> statistika(evidenca_1)
{'Špela': 1, 'Cilka': 3, 'Bojan': 4, 'Samo': 2, 'Klemen': 1}
def statistika(evidenca): drugovi = set() for v in evidenca.values(): drugovi.update(v) if None in drugovi: drugovi.remove(None) return {druze: len(zgodovina(evidenca, druze)) for druze in drugovi}
Sestavite funkcijo palindrom(niz)
, ki vrne True
kadar je niz
palindrom, in False
sicer.
def palindrom(niz): return niz == niz[::-1]
Pravimo, da je beseda praktično palindrom, če ji je treba zbrisati natanko
eno črko, da bi postala palindrom. Primer je beseda kolo
, ki ji
moramo zbrisati črko k
, pa postane palindrom olo
.
Sestavite funkcijo prakticno_palindrom(niz)
, ki preveri, ali je niz
priktično palindrom. Vse znake (tudi presledke) v besedi obravnavamo enako.
def prakticno_palindrom(niz): # za vsak i poskusimo izpustiti črko na i-tem mestu for i in range(len(niz)): # če smo dobili palindrom, končamo if palindrom(niz[:i] + niz[i + 1:]): return True # če je zanka prišla do konca, palindroma nismo našli return False
Pravimo, da je beseda skoraj palindrom, če ji je treba dodati ali izbrisati natanko eno črko oziroma zamenjati natanko eno črko z drugo, da bi postala palindrom. Primeri:
robot
, kjer moramo t
zamenjati z r
,jana
, kjer moramo na konec dodati j
.Sestavite funkcijo skoraj_palindrom(niz)
, ki preveri, ali je niz
skoraj palindrom. Vse znake (tudi presledke) v besedi obravnavamo enako.
def skoraj_palindrom(niz): # Odstranjevanje in dodajanje črk preverimo s funkcijo prakticno_palindrom. # Razmislite, zakaj smo s tem pokrili tudi dodajanje ene črke. if prakticno_palindrom(niz): return True # Za vsak i poskusimo črko na i-tem mestu nadomestiti s pravilno. for i in range(len(niz)): if palindrom(niz[:i] + niz[-i - 1] + niz[i + 1:]): return True # Če je zanka prišla do konca, palindroma z zamenjavo ene črke nismo našli. return False
Sestavite funkcijo je_prestopno(leto)
, ki vrne True
, kadar je leto
prestopno, in False
, kadar ni.
def je_prestopno(leto): return leto % 4 == 0 and leto % 100 != 0 or leto % 400 == 0
Sestavite funkcijo stevilo_dni(mesec, leto)
, ki vrne število dni danega
meseca (podanega s številom med 1 in 12) v danem letu.
def stevilo_dni(mesec, leto): if mesec == 2 and je_prestopno(leto): return 29 elif mesec == 2: return 28 elif mesec == 4 or mesec == 6 or mesec == 9 or mesec == 11: return 30 else: return 31
Sestavite funkcijo je_veljaven_datum(dan, mesec, leto)
, ki vrne True
natanko tedaj, kadar dan
, mesec
in leto
določajo veljaven datum
(torej mesec
mora biti število med 1 in 12, dan
pa mora ustrezati dnevu
v tem mesecu).
def je_veljaven_datum(dan, mesec, leto): return 1 <= mesec <= 12 and 1 <= dan <= stevilo_dni(mesec, leto)
http://lusy.fri.uni-lj.si/ucbenik/book/1205/index14.html
Naslednja funkcija naj bi vrnila število elementov tabele a
, ki
so manjši od x
, vendar vsebuje napake. Popravi jo.
def kolikoManjsih(a, x):
n = len(a)
koliko = 0
for i in xrange(1, n):
if a[i] != x:
koliko = 1
def kolikoManjsih(a, x): n = len(a) koliko = 0 for i in range(0, n): if a[i] < x: koliko += 1 return koliko
Dan je razred
def Uporabnik:
def init(ime, priimek):
self.ime = ime
self.priimek = priimek
def __str__(self)
print(ime + " " + priimek)
Popravi napake v definiciji razreda. Atributa naj ostaneta ime
in priimek
.
>>> jan = Uporabnik('Jan', 'Tisti')
>>> print(jan)
Jan Tisti
>>> jan.priimek
Tisti
>>> kitajc = Uporabnik('A', 'Li')
>>> print(kitajc)
A Li
>>> kitajc.ime
A
class Uporabnik: def __init__(self, ime, priimek): self.ime = ime self.priimek = priimek def __str__(self): return(self.ime + " " + self.priimek)
Spremeni konstruktor tako, da ne bo sprejemal imen in priimkov skupaj krajših od 5 črk.V tem primeru naj bo uporabnik Janez Slovenski.
>>> jan = Uporabnik('Jan', 'Tisti')
>>> print(jan)
Jan Tisti
>>> jan.priimek
Tisti
>>> kitajc = Uporabnik('A', 'Li')
>>> print(kitajc)
Janez Slovenski
>>> kitajc.ime
Janez
class Uporabnik: def __init__(self, ime, priimek): if len(ime+priimek) < 5: ime = 'Janez' priimek = 'Slovenski' self.ime = ime self.priimek = priimek def __str__(self): return(self.ime + " " + self.priimek)
Dodaj metodo inicialke, ki vrne inicialke uporabnika. Pri tem predpostavi, da ima vsak ime in priimek iz ene besede.
>>> jan = Uporabnik('Jan', 'Tisti')
>>> jan.inicialke()
J.T.
>>> legenda = Uporabnik('Bruce', 'Lee')
>>> legenda.inicialke()
B.L.
class Uporabnik: def __init__(self, ime, priimek): if len(ime+priimek) < 5: ime = 'Janez' priimek = 'Slovenski' self.ime = ime self.priimek = priimek def __str__(self): return(self.ime + " " + self.priimek) def inicialke(self): return self.ime[0] + '.' + self.priimek[0] + '.'
Ho Ši Minh se je pritožil in rekel, da so njegove inicialke H.Š.M. Podprla ga je tudi Ana Nina Vodičar Mehle, katere inicialke so po njenem A.N.V.M. . Peter Pavlovič Čehov pa je povedal, da se Ana Nina zmišljuje in da so njegove inicialke le P.Č. Da pa je bila zadeva še bolj zaostrena, se je v pogovor vmešal še Sebastian, ki pravi, da so njegove inicialke pač samo S.
Ker jim želiš vsem ustreči, dodaj še metodo polne_inicialke
tako, da bo imela parameter polno. Če bo nastavljen na True,
so inicialke sestavljene iz začetnic vseh besed, ki sestavljajo ime in priimek. Pri tem štejemo, da ime Ana Marija
sestavljata dve besedi, ime Ana-Nuša
pa le ena. Privzeta vrednost tega parametra pa je
False, kar pomeni, da se vzame le prva črka imena in prva črka priimka (razen za tako pomembne osebe, kot so Sebastian
ali pa Sting, ki so pač poznani le po imenu ali priimku - inicialke za oba sta S.
).
>>> jan = Uporabnik('Jan Jankovski', 'Tisti')
>>> jan.polne_inicialke(True)
J.J.T.
>>> jan = Uporabnik('Jan Jankovski', 'Tisti')
>>> jan.polne_inicialke()
J.T.
>>> jan = Uporabnik('Jan Jankovski', 'Tisti')
>>> jan.polne_inicialke(False)
J.T.
class Uporabnik: def __init__(self, ime, priimek): if len(ime + priimek) < 5: ime = 'Janez' priimek = 'Slovenski' self.ime = ime self.priimek = priimek def __str__(self): return (self.ime + " " + self.priimek) def polne_inicialke(self, polno = False): imena = self.ime.split() priimki = self.priimek.split() ini = '' for im in imena: ini += im[0] + '.' if not polno: break # le prvo for im in priimki: ini += im[0] + '.' if not polno: break # le prvo return ini
Trenutno je na spletu zelo popularna digitalna valuta
Bitcoin.
Osnova za pošteno uporabo take valute so zapleteni kriptografski
protokoli, mi pa bomo ubrali malo bolj poenostavljeno različico ter
sestavili razred BitniCekin
, s katerim bomo predstavili račun nekega
lastnika te valute.
POZOR:
Da ne bo težav pri testiranju, pri 2., 3. in 4. podnalogi začnemo z
class BitniCekini(BitniCekini):
To pomeni, da se v razred "skopirajo" vse definicije, ki ste jih v razred BitniCekini napisali prej. Seveda pa 1. podnalogo še vedno začnemo z
class BitniCekini():
Druga možnost pa je, da podanloge vedno začnemo z
class BitniCekini():
a potem v razred vedno napišemo vse metode, ki smo jih definirali v vseh prejšnjih podnalogah!
Sestavite razred BitniCekin
s konstruktorjem __init__(self, stanje)
,
ki sprejme začetno stanje na računu uporabnika (v valuti Bitcoin).
Atribut, v katerega shranite stanje, naj bo poimenovan _stanje
.
Argument stanje
naj bo neobvezen in v primeru, ko ni podan, naj bo
začetno stanje enako nič.
class BitniCekin: def __init__(self, stanje=0): self._stanje = stanje
Sestavite metodo __str__(self)
, ki predstavi stanje na računu v obliki:
'Število bitnih cekinov na računu: ...'
Primer:
>>> racun = BitniCekin(6)
>>> print(racun)
Število bitnih cekinov na računu: 6
class BitniCekin: def __init__(self, stanje=0): self._stanje = stanje def __str__(self): return 'Število bitnih cekinov na računu: {}'.format(self._stanje)
Sestavite metodi dvig(self, koliko)
in polog(self, koliko)
, ki
dvigneta oz. položita ustrezno količino bitnih cekinov na račun.
Predpostavimo, da bo vrednost argumenta koliko
vedno nenegativno
celo število.
Pri metodi dvig
upoštevajte, da stanje na računu ne sme biti negativno.
V takšnem primeru se dvig ne sme izvesti.
Metoda dvig
naj vrne True
, če je dvig uspel in False
, če ni.
Metoda polog
naj vrne stanje na računu po pologu.
class BitniCekin: def __init__(self, stanje=0): self._stanje = stanje def __str__(self): return 'Število bitnih cekinov na računu: {}'.format(self._stanje) def dvig(self, koliko): '''dvig sresdtev in potrditev uspešnosti transakcije''' if koliko > self._stanje: return False else: self._stanje -= koliko return True def polog(self, koliko): '''polog sredstev in vrednost trenutnega stanja''' self._stanje += koliko return self._stanje
Sestavite funkcijo prenesi(racun1, racun2, koliko)
, ki iz računa racun1
prenese koliko
cekinov na račun racun2
. Funkcija prenesi
naj ne bo
znotraj razreda BitniCekin
, saj ni objektna metoda, ampak je čisto običajna
funkcija. Spremenljivki racun1
in racun2
sta seveda objekta tipa BitniCekin
,
kar ni potrebno preverjati!
Če na računu racun1
ni dovolj denarja, se transakcija ne sme
izvršiti, torej mora stanje na obeh računih ostati nespremenjeno.
Funkcija naj vrne uspešnost transakcije (True
, če je transakcija uspela,
in False
, če ni).
def prenesi(racun1, racun2, koliko): '''prenos iz enega bitnega cekina na drugega in indikacija uspešnosti transakcije ''' if racun1.dvig(koliko): racun2.polog(koliko) return True return False
POZOR:
Da ne bo težav pri testiranju, pri 2., 3., 4. in 5. podnalogi začnemo z
class Datumi(Datumi):
To pomeni, da se v razred "skopirajo" vse definicije, ki ste jih v razred Datumi napisali prej. Seveda pa 1. podnalogo še vedno začnemo z
class Datumi():
Druga možnost pa je, da podanloge vedno začnemo z
class Datumi():
a potem v razred vedno napišemo vse metode, ki smo jih definirali v vseh prejšnjih podnalogah!
Definirajte razred Datum
, s katerim predstavimo datum. Najprej
sestavite konstruktor __init__(self, dan, mesec, leto)
. Atributi
razreda Datum
naj bodo poimenovani _dan
, _mesec
in _leto
.
>>> d = Datum(21, 5, 2013)
>>> d.leto
2013
class Datum: def __init__(self, dan, mesec, leto): self._dan = dan self._mesec = mesec self._leto = leto
Razredu Datum dodajte (torej vaš razred mora vsebovati to, kar zahteva 1. naloga)
metodo __str__
, ki predstavi datum v berljivi obliki
'dan. mesec. leto'
.
>>> d = Datum(21, 5, 2013)
>>> print(d)
21. 5. 2013
class Datum: def __init__(self, dan, mesec, leto): self._dan = dan self._mesec = mesec self._leto = leto def __str__(self): return "{0}. {1}. {2}".format(self._dan, self._mesec, self._leto)
Razredu Datum dodajte (torej vaš razred mora vsebovati to, kar zahteva 1. naloga)
metodo __lt__
, ki datum primerja z drugim datumom
(metoda naj vrne True
, če je prvi datum manjši, in False
, če ni).
Ko definirate to metodo, lahko datume primerjate kar z operatorjema
<
in >
. Na primer:
>>> Datum(31, 12, 1999) < Datum(1, 1, 2000)
True
class Datum: def __init__(self, dan, mesec, leto): self._dan = dan self._mesec = mesec self._leto = leto def __str__(self): return "{0}. {1}. {2}".format(self._dan, self._mesec, self._leto) def __lt__(self, other): # uporabimo Pythonovo vgrajeno leksikografsko primerjavo return (self._leto, self._mesec, self._dan) < (other._leto, other._mesec, other._dan)
Razredu Datum dodajte (torej vaš razred mora vsebovati to, kar zahteva 1. naloga)
metodo __eq__
, ki datum primerja z drugim datumom
(metoda naj vrne True
, če sta datuma enaka, in False
, če nista).
Ko definirate to metodo, lahko datume primerjate kar z operatorjema
==
in !=
. Na primer:
>>> Datum(31, 12, 1999) != Datum(1, 1, 2000)
True
class Datum: def __init__(self, dan, mesec, leto): self._dan = dan self._mesec = mesec self._leto = leto def __eq__(self, other): # uporabimo Pythonovo vgrajeno leksikografsko primerjavo return (self._leto, self._mesec, self._dan) == (other._leto, other._mesec, other._dan)
Razredu Datum dodajte (torej vaš razred mora vsebovati to, kar zahteva 1. naloga)
metodo iso8601
, ki vrne niz s predstavitvijo datuma oblike
yyyy-mm-dd
. Na prvem mestu je letnica, nato mesec in na koncu dan.
Števila so ločena z znaki '-'
. Letnica je štirimestno število, dan
in mesec pa dvomestni števili (po potrebi jih dopolnite z vodilnimi
ničlami.
>>> Datum(17, 3, 1999).iso8601()
'1999-03-17'
class Datum: def __init__(self, dan, mesec, leto): self._dan = dan self._mesec = mesec self._leto = leto def iso8601(self): return "{0:04}-{1:02}-{2:02}".format(self._leto, self._mesec, self._dan)
Definirajte razred Bakterija
, s katerim bomo predstavili bakterije.
Sestavite konstruktor, ki kot parameter sprejema niz, ki opisuje genski zapis bakterije in ta niz priredi atributu DNA
.
Preveriti pa morate, če je dani genski zapis veljaven, se pravi, da vsebuje samo črke 'A'
,'G'
,'C'
,'T'
(okrajšave za adenin, gvanin, citozin in timin). Če niz ni veljaven, naj atribut DNA
postane prazen niz.
Konstruktor mora narediti tudi atribut generacija
, ki naj dobi začetno vrednost 0
.
Primer:
>>> a = Bakterija('GAAATCGGT')
>>> a.DNA
'GAAATCGGT'
>>> a.generacija
0
Primer z neveljavnim genskim zapisom:
>>> a = Bakterija('ABCDEFGH')
>>> a.DNA
''
class Bakterija: def __init__(self, dna): self.DNA = dna if all([x in 'ACGT' for x in dna]) else '' self.generacija = 0 # če vam razumevanje zgornje kode dela težave - stvar bi lahko # napisali tudi # self.DNA = dna # # ali morda ni veljavno? # for znak in dna: # if znak not in 'ACGT': # self.DNA = '' # napačen znak, zato ... # break # self.generacija = 0
Bakterije se zelo rade delijo. Običajne bakterije delijo tako, da iz ene nastaneta dve novi, naše bakterije pa so posplošene bakterije, ki se lahko delijo na poljubno število novih bakterij. Pri tem se njihov genski zapis prekopira, poveča pa se števec generacije.
Definirajte metodo __floordiv__
, s katero je definirana operacija //
(celoštevilčno deljenje).
Metoda sprejema le en parameter (delitelj), ki pove, koliko bakterij dobimo po delitvi.
Metoda mora vrniti seznam novih bakterij, ki imajo isti DNA
kot začetna bakterija,
imajo pa povečan števec generacije.
Pri tem pa morate še upoštevati, da se bakterije s praznim genskim zapisom ne morejo deliti. V takšnem primeru
naj metoda vrne prazen seznam.
Primer:
>>> a = Bakterija('GAAATCGGT')
>>> nove_bakterije = a//3
>>> len(nove_bakterije)
3
>>> print(nove_bakterije)
[<__main__.Bakterija object at 0x7ffd41edac50>, <__main__.Bakterija object at 0x7ffd41edab90>, <__main__.Bakterija object at 0x7ffd41edab50>]
>>> nove_bakterije[0].generacija
1
>>> nove_bakterije[0].DNA
'GAAATCGGT'
class Bakterija(Bakterija): # zgornji zapis pomeni, da "poberemo" vse, kar smo do sedaj # že napisali v razredu Bakterija def __floordiv__(self, n): if not self.DNA: return [] nove = [] for i in range(n): b = Bakterija(self.DNA) b.generacija = self.generacija + 1 nove.append(b) return nove
Bakterije se lahko tudi združujejo. Pri tem nastane nova bakterija,
katere genski zapis je kombinacija genskih zapisov obeh bakterij, ki nastopata v združevanju.
Zapis se združuje po takšnem pravilu: izmenično se jemlje po eno črko iz
obeh genskih zapisov, ko pa pridemo do konca krajšega genskega zapisa, se preostanek daljšega
doda na konec novega zapisa.
Tako bi na primer pri združevanju zapisov ACT
in GCTATGCCC
dobili AGCCTTATGCCC
.
Definirajte metodo __add__
, s katero je definirana operacija +
(seštevanje).
To pomeni, da bomo bakterije lahko združevali kar z uporabo operatorja +
.
Metoda sprejema en parameter: drugo bakterijo, ki jo bomo združili s prvo.
Metoda naj vrne novo bakterijo, ki ima združen genski zapis ter za ena večji števec generacije kot
starejša od obeh bakterij, ki nastopata v združevanju.
Primer:
>>> a = Bakterija('ACT')
>>> b = Bakterija('GCTATGCCC')
>>> c = a + b
>>> c.DNA
'AGCCTTATGCCC'
>>> c.generacija
1
class Bakterija(Bakterija): # zgornji zapis pomeni, da "poberemo" vse, kar smo do sedaj # že napisali v razredu Bakterija def __add__(self, other): dna = '' ml = min(len(self.DNA), len(other.DNA)) for i in range(ml): dna += self.DNA[i] + other.DNA[i] dna += self.DNA[ml:] + other.DNA[ml:] nova = Bakterija(dna) nova.generacija = 1 + max(self.generacija, other.generacija) return nova
Bakterije lahko tudi mutirajo, pri čemer se jim spremeni genski zapis.
Na primer, podzaporedje AAG
se pri mutaciji spremeni v podzaporedje AAT
.
Pri mutaciji se vedno spremenijo vse pojavitve danega podzaporedja, če pa genski
zapis bakterije takšnega podzaporedja ne vsebuje, pa se med mutacijo DNA seveda ne spremeni.
Napišite metodo mutacija
, ki sprejme dva parametra, ki povesta,
v kaj se pri mutaciji spremeni dano podzaporedje genskega zapisa.
Metoda naj vrne novo bakterijo, ki ima mutiran genski zapis in za ena večji
števec generacije.
Upoštevajte, da se mutacije genskega zapisa vedno odvijajo v smeri od leve proti desni
(običajna smer v katero naraščajo indeksi).
Upoštevajte tudi, da bakterije brez genskega zapisa ne morejo mutirati. V takšnem
primeru naj metoda vrne isto, nespremenjeno bakterijo (nasvet: self
).
Nasvet: pomagajte si z metodo replace
!
Primer:
>>> a = Bakterija('GAAATCGGT')
>>> m = a.mutacija('AAT', 'CAT')
>>> m.DNA
'GACATCGGT'
>>> m.generacija
1
class Bakterija(Bakterija): # zgornji zapis pomeni, da "poberemo" vse, kar smo do sedaj # že napisali v razredu Bakterija def mutacija(self, fr, to): if not self.DNA: return self MDNA = self.DNA.replace(fr, to) nova = Bakterija(MDNA) nova.generacija = self.generacija + 1 return nova
Mnogokotnik v ravnini lahko predstavimo s seznamom njegovih oglišč (pari števil). Na primer seznam
[(0, 0), (1, 0), (1, 1), (0, 1)]
opisuje kvadrat, seznam
[(2, 0), (2, 1), (0, 2), (-2, 1), (-2, 0), (0, 1)]
pa opisuje (nekonveksen) šestkotnik.
Sestavite razred Mnogokotnik
, s katerim predstavimo ravninski
mnogokotnik. Najprej sestavite konstruktor __init__(self, ogl)
,
kjer je ogl
seznam njegovih oglišč. Atribut razreda naj bo
poimenovan oglisca
.
Nekateri ljudje mnogokotnike zapisujejo tako, da na konec seznama oglišč ponovno postavijo prvo oglišče (s tem poudarijo, da je mnogokotnik sklenjen). Zgornji kvadrat bi torej zapisali takole:
[(0, 0), (1, 0), (1, 1), (0, 1), (0, 0)]
V našem razredu Mnogokotnik
naj se dolžina seznama oglisca
ujema s
številom oglišč mnogokotnika. Podvojeno oglišče na koncu seznama naj
konstruktor po potrebi odstrani. Zgled:
>>> p = Mnogokotnik([(0, 0), (1, 0), (1, 1), (0, 1), (0, 0)])
>>> p.oglisca
[(0, 0), (1, 0), (1, 1), (0, 1)]
Predpostavite lahko, da mnogokotniki ne bodo izrojeni (tj. če imata dve stranici neprazen presek, sta nujno sosednji, presek pa je natanko njuno skupno oglišče).
class Mnogokotnik(object): def __init__(self, oglisca): self.oglisca = list(oglisca) if self.oglisca[0] == self.oglisca[-1]: self.oglisca.pop()
V razredu Mnogokotnik
definirajte metodo obseg(self)
, ki izračuna in
vrne njegov obseg. Zgled:
>>> p = Mnogokotnik([(0, 0), (1, 0), (1, 1), (0, 1), (0, 0)])
>>> p.obseg()
4.0
def dolzina_daljice(a, b): ax, ay = a bx, by = b return ((ax - bx) ** 2 + (ay - by) ** 2) ** 0.5 class Mnogokotnik(Mnogokotnik): def obseg(self): ob = 0 n = len(self.oglisca) for i in range(n): ob += dolzina_daljice(self.oglisca[i], self.oglisca[(i + 1) % n]) return ob
V razredu Mnogokotnik
definirajte metodo ploscina(self)
, ki izračuna
in vrne njegovo ploščino.
Ploščina mnogokotnika (brez samopresečišč) z oglišči
>>> p = Mnogokotnik([(0, 0), (1, 0), (1, 1), (0, 1)])
>>> p.ploscina()
1.0
class Mnogokotnik(Mnogokotnik): def ploscina(self): a = 0 n = len(self.oglisca) for i in range(n): x, y = self.oglisca[i] x2, y2 = self.oglisca[(i + 1) % n] a += x * y2 - x2 * y return abs(a) / 2
V razredu Mnogokotnik
definirajte metodo je_konveksen(self)
, ki
vrne True
, če je mnogokotnik konveksen in False
sicer.
Predstavljajte si, da je ravnina, na kateri leži mnogokotnik, vložena v
trirazsežni prostor tako, da je
>>> p = Mnogokotnik([(0, 0), (1, 0), (1, 1), (0, 1)])
>>> p.je_konveksen()
True
>>> q = Mnogokotnik([(2, 0), (2, 1), (0, 2), (-2, 1), (-2, 0), (0, 1)])
>>> q.je_konveksen()
False
Predpostavite lahko, da nobeni dve zaporedni stranici ne oklepata iztegnjenega kota (180 °).
def vektorski_produkt(a, b): ax, ay, az = a bx, by, bz = b return (ay * bz - az * by, az * bx - ax * bz, ax * by - ay * bx) def smer_vrtenja(u, v, w): ux, uy = u vx, vy = v wx, wy = w z = vektorski_produkt((vx - ux, vy - uy, 0), (wx - vx, wy - vy, 0))[2] return 1 if z > 0 else -1 class Mnogokotnik(Mnogokotnik): def je_konveksen(self): n = len(self.oglisca) znak = smer_vrtenja(self.oglisca[0], self.oglisca[1], self.oglisca[2]) for i in range(1, n): u = self.oglisca[i % n] v = self.oglisca[(i + 1) % n] w = self.oglisca[(i + 2) % n] znak2 = smer_vrtenja(u, v, w) if znak2 * znak < 0: return False return True
POZOR:
Da ne bo težav pri testiranju, pri vseh podnalogah začnemo z
class Ulomek(Ulomek):
To pomeni, da se v razred "skopirajo" vse definicije, ki ste jih v razred Ulomek napisali prej. Seveda pa 1. podnalogo še vedno začnemo z
class Ulomek():
Druga možnost pa je, da podnaloge vedno začnemo z
class Ulomek():
a potem v razred vedno napišemo vse metode, ki smo jih definirali v vseh prejšnjih podnalogah!
Izven razreda sestavite funkcijo gcd(m, n)
, ki izračuna največji skupni
delitelj števil m
in n
.
def gcd(m, n): while n != 0: m, n = n, m % n return m
Definirajte razred Ulomek
, s katerim predstavimo ulomek. Števec in
imenovalec sta celi števili, pri čemer je morebiten negativen predznak
vedno v števcu. Komponenti naj se imenujeta _st
in _im
.
Ulomki naj bodo vedno okrajšani.
Najprej definirajte konstruktor __init__(self, st, im)
.
class Ulomek: def __init__(self, st, im): if im < 0: st, im = -st, -im d = gcd(st, im) self._st = st // d self._im = im // d
Definirajte metodo __str__
, ki predstavi ulomek v obliki "st/im"
.
class Ulomek(Ulomek): def __str__(self): return "{0}/{1}".format(self._st, self._im)
Definirajte metodo __eq__
, ki vrne True
če sta dva ulomka
enaka, in False
sicer.
class Ulomek(Ulomek): def __eq__(self, other): return self._st == other._st and self._im == other._im
Definirajte metodo __add__
, ki vrne vsoto dveh ulomkov.
Ko definirate to metodo, lahko ulomke seštevate kar z operatorjem +
.
Na primer:
>>> print(Ulomek(1, 6) + Ulomek(1, 4))
5/12
class Ulomek(Ulomek): def __add__(self, other): a, b = self._st, self._im c, d = other._st, other._im return Ulomek(a * d + b * c, b * d)
Definirajte metodo __sub__
, ki vrne razliko dveh ulomkov.
Ko definirate to metodo, lahko ulomke odštevate kar z operatorjem -
.
class Ulomek(Ulomek): def __sub__(self, other): a, b = self._st, self._im c, d = other._st, other._im return Ulomek(a * d - b * c, b * d)
Definirajte metodo __mul__
, ki vrne zmnožek dveh ulomkov.
Ko definirate to metodo, lahko ulomke množite kar z operatorjem *
.
class Ulomek(Ulomek): def __mul__(self, other): a, b = self._st, self._im c, d = other._st, other._im return Ulomek(a * c, b * d)
Definirajte metodo __truediv__
, ki vrne kvocient dveh ulomkov.
Ko definirate to metodo, lahko ulomke delite kar z operatorjem /
.
class Ulomek(Ulomek): def __truediv__(self, other): a, b = self._st, self._im c, d = other._st, other._im return Ulomek(a * d, b * c)
Definirajte funkcijo priblizek(n)
, ki vrne vsoto
def priblizek(n): def fakulteta(i): return 1 if i == 0 else i * fakulteta(i - 1) return sum((Ulomek(1, fakulteta(i)) for i in range(n + 1)), Ulomek(0, 1))
Dan je razred Drevo
, ki predstavlja dvojiško drevo. Za osnovno vzemite
naslednjo kodo:
class Drevo:
def __init__(self, *args, **kwargs):
if args:
self.prazno = False
self.vsebina = args[0]
self.levo = kwargs.get('levo', Drevo())
self.desno = kwargs.get('desno', Drevo())
else:
self.prazno = True
def __repr__(self, zamik=''):
if self.prazno:
return 'Drevo()'.format(zamik)
elif self.levo.prazno and self.desno.prazno:
return 'Drevo({1})'.format(zamik, self.vsebina)
else:
return 'Drevo({1},\n{0} levo = {2},\n{0} desno = {3})'.\
format(
zamik,
self.vsebina,
self.levo.__repr__(zamik + ' '),
self.desno.__repr__(zamik + ' ')
)
def __eq__(self, other):
return ((self.prazno and other.prazno) or
(not self.prazno and not other.prazno and
self.vsebina == other.vsebina and
self.levo == other.levo and
self.desno == other.desno))
Konstruktor je že implementiran; prav tako metodi __repr__
in __eq__
.
Drevo na spodnji (ASCII art) sliki:
5
/ \
3 2
/ / \
1 6 9
sestavimo takole:
>>> d = Drevo(5,
levo=Drevo(3, levo=Drevo(1)),
desno=Drevo(2, levo=Drevo(6), desno=Drevo(9)))
Razredu dodajte metodo vsota(self)
, ki vrne vsoto vseh števil v drevesu.
Zgled (kjer je d
kot zgoraj):
>>> d.vsota()
26
class Drevo: def __init__(self, *args, **kwargs): if args: self.prazno = False self.vsebina = args[0] self.levo = kwargs.get('levo', Drevo()) self.desno = kwargs.get('desno', Drevo()) else: self.prazno = True def __repr__(self, zamik=''): if self.prazno: return 'Drevo()'.format(zamik) elif self.levo.prazno and self.desno.prazno: return 'Drevo({1})'.format(zamik, self.vsebina) else: return 'Drevo({1},\n{0} levo = {2},\n{0} desno = {3})'.\ format( zamik, self.vsebina, self.levo.__repr__(zamik + ' '), self.desno.__repr__(zamik + ' ') ) def __eq__(self, other): return ((self.prazno and other.prazno) or (not self.prazno and not other.prazno and self.vsebina == other.vsebina and self.levo == other.levo and self.desno == other.desno)) def vsota(self): if self.prazno: return 0 else: return self.vsebina + self.levo.vsota() + self.desno.vsota()
Dodajte metodo stevilo_listov(self)
, ki vrne število listov v drevesu.
Zgled (kjer je d
kot zgoraj):
>>> d.stevilo_listov()
3
class Drevo(): def __init__(self, *args, **kwargs): if args: self.prazno = False self.vsebina = args[0] self.levo = kwargs.get('levo', Drevo()) self.desno = kwargs.get('desno', Drevo()) else: self.prazno = True def __repr__(self, zamik=''): if self.prazno: return 'Drevo()'.format(zamik) elif self.levo.prazno and self.desno.prazno: return 'Drevo({1})'.format(zamik, self.vsebina) else: return 'Drevo({1},\n{0} levo = {2},\n{0} desno = {3})'. \ format( zamik, self.vsebina, self.levo.__repr__(zamik + ' '), self.desno.__repr__(zamik + ' ') ) def __eq__(self, other): return ((self.prazno and other.prazno) or (not self.prazno and not other.prazno and self.vsebina == other.vsebina and self.levo == other.levo and self.desno == other.desno)) def vsota(self): if self.prazno: return 0 else: return self.vsebina + self.levo.vsota() + self.desno.vsota() def stevilo_listov(self): if self.prazno: return 0 elif self.levo.prazno and self.desno.prazno: return 1 else: return self.levo.stevilo_listov() + self.desno.stevilo_listov()
Dodajte metodo minimum(self)
, ki vrne najmanjše število v drevesu.
Če je drevo prazno, naj metoda vrne None
. Zgled (kjer je d
kot
zgoraj):
>>> d.minimum()
1
>>> Drevo().minimum()
None
class Drevo(Drevo): def __init__(self, *args, **kwargs): if args: self.prazno = False self.vsebina = args[0] self.levo = kwargs.get('levo', Drevo()) self.desno = kwargs.get('desno', Drevo()) else: self.prazno = True def __repr__(self, zamik=''): if self.prazno: return 'Drevo()'.format(zamik) elif self.levo.prazno and self.desno.prazno: return 'Drevo({1})'.format(zamik, self.vsebina) else: return 'Drevo({1},\n{0} levo = {2},\n{0} desno = {3})'. \ format( zamik, self.vsebina, self.levo.__repr__(zamik + ' '), self.desno.__repr__(zamik + ' ') ) def __eq__(self, other): return ((self.prazno and other.prazno) or (not self.prazno and not other.prazno and self.vsebina == other.vsebina and self.levo == other.levo and self.desno == other.desno)) def vsota(self): if self.prazno: return 0 else: return self.vsebina + self.levo.vsota() + self.desno.vsota() def stevilo_listov(self): if self.prazno: return 0 elif self.levo.prazno and self.desno.prazno: return 1 else: return self.levo.stevilo_listov() + self.desno.stevilo_listov() def minimum(self): if self.prazno: return None else: # Vrednost izraza `a or b` je `a`, če je `bool(a) == True`, # in `b` sicer. Torej, to je ekvivalentno izrazu `a if a else b`. # Opomba: `bool(None) == False`. levi_minimum = self.levo.minimum() or float('inf') desni_minimum = self.desno.minimum() or float('inf') return min(self.vsebina, levi_minimum, desni_minimum)
V neki mafijski organizaciji so člani urejeni hierarhično. Vsakdo razen botra (vrhovnega šefa) ima natanko enega nadrejenega. Vsak mafijec ima lahko pod seboj največ dva podrejena (levega in desnega). Primer takšne mafijske organizacije:
mafija = Drevo('Salvatore', 320,
levo=Drevo('Bernardo', 200,
levo=Drevo('Matteo', 50),
desno=Drevo('Carlo', 100,
levo=Drevo('Rosalia', 70),
desno=Drevo('Tommaso', 50))),
desno=Drevo('Francesco', 120,
levo=Drevo('Giuseppe', 70),
desno=Drevo('Antonio', 60)))
Mafijci morajo zbirati denar s kriminalnimi dejavnostmi. Tisti, ki imajo podrejene, pa ga poleg tega poberejo še od svojih podrejenih. Ves “prisluženi” in prejeti denar morajo oddati svojemu nadrejenemu.
Boter je posumil, da nekateri člani goljufajo. Nekaj denarja, ki ga
poberejo od podrejenih, zadržijo zase. Od vsakega člana je pridobil
podatek o tem, koliko denarja je oddal naprej. Podatke je shranil v
podatkovno strukturo Drevo
, ki je že implementirana.
Botra zanima, koliko denarja zaradi goljufov “ponikne”. Želi, da
sestavite metodo koliko_ponikne(self)
, ki vrne skupno vsoto denarja,
ki ponikne. Primer (če mafija
ustreza zgornjemu drevesu):
>>> mafija.koliko_ponikne()
30
class Drevo: def __init__(self, *args, **kwargs): if len(args) > 0: self.prazno = False self.ime = args[0] self.vrednost = args[1] self.levo = kwargs.get('levo', Drevo()) self.desno = kwargs.get('desno', Drevo()) else: self.prazno = True def __repr__(self): if self.prazno: return 'Drevo()' else: opis = repr(self.ime) + ', ' + repr(self.vrednost) if not self.levo.prazno: opis += ', levo={0}'.format(self.levo) if not self.desno.prazno: opis += ', desno={0}'.format(self.desno) return 'Drevo({0})'.format(opis) def get_vrednost(self): return self.vrednost if not self.prazno else 0 def koliko_ponikne(self): if self.prazno: return 0 utajil = max(self.levo.get_vrednost() + self.desno.get_vrednost() - self.get_vrednost(), 0) return utajil + self.levo.koliko_ponikne() + self.desno.koliko_ponikne()
Ko je boter dognal, koliko denarja ponikne, je totalno po████. Pri
priči hoče imeti imena vseh goljufov! Napišite metodo goljufi(self)
,
ki vrne množico goljufov. Vsak goljuf naj bo predstavljen z naborom.
Prva kompotenta naj bo ime goljufa, druga komponenta pa količina denarja,
ki ga je utajil. Primer:
>>> mafija.goljufi()
{(’Carlo’, 20), (’Francesco’, 10)}
class Drevo: def __init__(self, *args, **kwargs): if len(args) > 0: self.prazno = False self.ime = args[0] self.vrednost = args[1] self.levo = kwargs.get('levo', Drevo()) self.desno = kwargs.get('desno', Drevo()) else: self.prazno = True def __repr__(self): if self.prazno: return 'Drevo()' else: opis = repr(self.ime) + ', ' + repr(self.vrednost) if not self.levo.prazno: opis += ', levo={0}'.format(self.levo) if not self.desno.prazno: opis += ', desno={0}'.format(self.desno) return 'Drevo({0})'.format(opis) def get_vrednost(self): return self.vrednost if not self.prazno else 0 def goljufi(self): if self.prazno: return set() utajil = max(self.levo.get_vrednost() + self.desno.get_vrednost() - self.get_vrednost(), 0) return ({(self.ime, utajil)} if utajil > 0 else set()) | self.levo.goljufi() | self.desno.goljufi()
Botru se dozdeva, da so najbolj pridne majhne ribe. To so tisti mafijci,
ki nimajo pod seboj nobenega podrejenega. Tistim, ki imajo podrejene, se
reče velike ribe. Napišite metodo zasluzek(self)
, ki vrne par (nabor)
dveh števili, pri čemer je:
Primer:
>>> mafija.zasluzek()
(300, 50)
class Drevo: def __init__(self, *args, **kwargs): if len(args) > 0: self.prazno = False self.ime = args[0] self.vrednost = args[1] self.levo = kwargs.get('levo', Drevo()) self.desno = kwargs.get('desno', Drevo()) else: self.prazno = True def __repr__(self): if self.prazno: return 'Drevo()' else: opis = repr(self.ime) + ', ' + repr(self.vrednost) if not self.levo.prazno: opis += ', levo={0}'.format(self.levo) if not self.desno.prazno: opis += ', desno={0}'.format(self.desno) return 'Drevo({0})'.format(opis) def get_vrednost(self): return self.vrednost if not self.prazno else 0 def zasluzek(self): if self.prazno: return 0, 0 l_male, l_velike = self.levo.zasluzek() d_male, d_velike = self.desno.zasluzek() mala = self.levo.prazno and self.desno.prazno prispevek = max(self.get_vrednost() - self.levo.get_vrednost() - self.desno.get_vrednost(), 0) m, v = l_male + d_male, l_velike + d_velike if mala: m += prispevek else: v += prispevek return m, v
Definirajte razred Polinom
, s katerim predstavimo polinom v
spremenljivki Polinom([7, 2, 0, 1])
.
Razmislite, kaj predstavlja Polinom([])
. Zadnji koeficient v seznamu
mora biti neničelen.
Sestavite konstruktor __init__(koef)
, ki nastavi tabelo koeficientov.
class Polinom: def __init__(self, koef): # že na začetku se znebimo vseh ničelnih vodilnih koeficientov zadnji = len(koef) while zadnji > 0 and koef[zadnji - 1] == 0: zadnji -= 1 self._koef = koef[:zadnji]
Sestavite metodo stopnja
, ki vrne stopnjo polinoma. Stopnja ničelnega
polinoma je v matematiki po dogovoru
class Polinom(Polinom): def stopnja(self): return len(self._koef) - 1
Sestavite metodo __eq__
za primerjanje polinomov.
class Polinom(Polinom): def __eq__(self, other): return self._koef == other._koef
Sestavite metodo __add__
za seštevanje polinomov.
Pozor: pri seštevanju se lahko zgodi, da se nekateri začetni
koeficienti pokrajšajo:
class Polinom(Polinom): def __add__(self, other): # predpostavimo, da ima levi polinom vsaj toliko členov kot desni if len(self._koef) < len(other._koef): return other + self # nato vzamemo levi polinom in kosoma prištevamo desnega koef_vsote = self._koef for n, a in enumerate(other._koef): koef_vsote[n] += a return Polinom(koef_vsote)
Sestavite metodo __mul__
za množenje polinomov.
class Polinom(Polinom): def __mul__(self, other): # če je eden od polinomov ničelen, je ničelen tudi produkt if not self._koef or not other._koef: return Polinom([]) # oba polinoma z ničlami podaljšamo do iste dolžine levi = self._koef + len(other._koef) * [0] desni = other._koef + len(self._koef) * [0] koef_prod = [sum(levi[i] * desni[n - i] for i in range(n + 1)) for n in range(len(levi))] return Polinom(koef_prod)
Sestavite metodo __str__
, ki predstavi polinom v čitljivi obliki.
>>> print(Polinom([1, -2, 3, -1]))
-x^3 + 3 x^2 - 2 x + 1
>>> print(Polinom([-1, 0, 0, 1]))
x^3 - 1
class Polinom(Polinom): def __str__(self): def monom(a, n): # Sestavimo si člen za monom. Na začetku in na koncu damo še oglate # oklepaje, ki jih bomo na koncu sicer pobrisali, da bomo vmes lahko # na poseben način obravnavali nekatere kombinacije znakov. monom = "[{0} x^{1}]".format(a, n) # popravimo potence in koeficiente monom = monom.replace("^1]", "") # ^1 pobrišemo le na koncu niza monom = monom.replace(" x^0", "") # pobrišemo presledek pred x^0 monom = monom.replace("[1 x", "x") # 1 mora biti na začetku monoma monom = monom.replace("-1 x", "-x") monom = monom.replace("[", "").replace("]", "") return monom # "seštejemo" vse momone z neničelnimi koeficienti # pred tem moramo koeficiente obrniti v vrstni red kot v izpisu niz = " + ".join(reversed([monom(a, n) for n, a in enumerate(self._koef) if a != 0])) niz = niz.replace("+ -", "- ") # popravimo negativne koeficiente # če smo dobili niz, ga vrnemo, sicer izpišemo ničelni polinom return niz or "0"
Vektorjem, ki vsebujejo veliko število ničelnih elementov, pravimo redki vektorji. Namesto običajne predstavitve, pri kateri navedemo vse elemente vektorja, lahko uporabimo bolj kompaktno predstavitev, kjer ničelne elemente izpustimo, za neničelne pa si zapomnimo, na katerih mestih so.
Primer: Vektor
a = [1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 4, 0, 0]
lahko namesto v obliki dolgega seznama z veliko ničlami zapišemo v kompaktni obliki kot slovar, kjer so ključi indeksi neničelnih elementov iz dolgega zapisa:
r = {0: 1, 10: 4, 5: 5, 6: 1}
Vrstni red indeksov seveda ni pomemben, saj imamo slovar. Ničelni vektor
predstavimo kar s praznim slovarjem {}
.
Napišite funkcijo stisni(vektor)
, ki sprejme vektor kot seznam števil
ter vrne redko obliko vektorja, tj. slovar, v katerem so ključi indeksi
neničelnih vrednosti, vrednosti pa te neničelne vrednosti.
Primer:
>>> stisni([1, 0, 0, 0, 0, 5, 1, 0, 0, 0, 4])
{0: 1, 10: 4, 5: 5, 6: 1}
>>> stisni([1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99])
{0: 1, 15: 99}
def stisni(vektor): '''vrne redko obliko vektorja, v obliki indeks : vrednost''' sv = dict() for i, x in enumerate(vektor): if x != 0: # zanimajo nas le neničelni elementi sv[i] = x return sv
Definirajte razred Vektor
, s katerim bomo predstavili redke vektorje.
Sestavite konstruktor, ki kot parameter sprejme vektor v stisnjeni obliki
(slovar) ter ga priredi atributu elementi
.
Sestavite še metodo __len__
, ki vrne število neničelih elementov redkega
vektorja. Metoda nima argumentov (razen obveznega argumenta self
, ki pove,
da gre za metodo danega razreda). Metoda __len__
se bo izvedla, kadar
bomo na objektu tipa Vektor
uporabili Pythonovo vgrajeno funkcijo len
,
kot je prikazano v spodnjem primeru.
Primer:
>>> a = Vektor({0: 1, 10: 4, 5: 5, 6: 1})
>>> a.elementi
{0: 1, 10: 4, 5: 5, 6: 1}
>>> len(a)
4
class Vektor: def __init__(self, data): self.elementi = data def __len__(self): return len(self.elementi)
Definirajte metodi __add__
in __sub__
, s katerima boste definirali
operatorja +
in -
nad objekti tipa Vektor
. Gre za običajno
seštevanje in odštevanje vektorjev, le da morate upoštevati, da seštevamo
oz. odštevamo redki obliki, ki sta predstavljeni s slovarjema.
Vsaka od metod sprejema en argument in sicer drugi vektor, ki nastopa v
aritmetični operaciji, vrne pa naj nov objekt tipa Vektor
, ki je vsota
oz. razlika danih vektorjev.
Nasvet: Upoštevajte, da so v rezultatu lahko neničelne vrednosti le na tistih indeksih, pri katerih je neničeln vsaj en od obeh operandov – pomagajte si z unijo obeh množic indeksov.
Primer:
>>> a = Vektor({0: 1})
>>> b = Vektor({0: 1, 3: 1})
>>> c = a + b
>>> c.elementi
{0: 2, 3: 1}
class Vektor(Vektor): def __add__(self, other): data = dict() keys = set(self.elementi).union(other.elementi) # set iz slovarja pobere le ključe! for k in keys: # poberemo k kar iz obeh, če ga ni, vzamemo 0 v = self.elementi.get(k, 0) + other.elementi.get(k, 0) if v != 0: # če se vrednosti nista izničili (negativna št!) data[k] = v return Vektor(data) def __sub__(self, other): data = dict() keys = set(self.elementi).union(other.elementi) # unija ključev, ker je set(slovar) istio kot set(slovar.keys()) for k in keys: v = self.elementi.get(k, 0) - other.elementi.get(k, 0) if v != 0: # če se vrednosti nista izničili data[k] = v return Vektor(data)
Definirajte še metodo razsiri
, ki vrne običajno (dolgo) obliko
vektorja. Pri tem se razširjena oblika ne sme končati z 0, saj drugače
razširitev ni enolična (glej drugi primer!)
Primer:
>>> a = Vektor(stisni([1, 0, 0, 0, 0, 0, 0, 0, 9]))
>>> a.elementi
{0: 1, 8: 9}
>>> a.razsiri()
[1, 0, 0, 0, 0, 0, 0, 0, 9]
>>> Vektor(stisni([1, 0, 0, 0])).razsiri()
[1]
class Vektor(Vektor): def razsiri(self): '''razpihne redki vektor v "običajno" obliko''' if self.elementi == dict(): return list() # prazen seznam else: # maksimalni indeks je maksimalna vrednost ključa v slovarju # vrednosti za vsak indeks bodo bodisi 0 bodisi ustrezne vrednosti iz slovarja return [self.elementi.get(i, 0) for i in range(max(self.elementi) + 1)]
Razred Vozel
predstavlja osnovni gradnik verižnega seznama. Pri tej nalogi
bomo dodali razredu Vozel
nekaj novih metod. Za osnovno vzemite naslednjo
implementacijo:
class Vozel:
"""
Osnovni sestavni del verižnega seznama.
"""
def __init__(self, podatek=None, naslednji=None):
self.podatek = podatek
self.naslednji = naslednji
def __str__(self):
return str(self.podatek)
Razredu Vozel
dodajte metodo vrni_seznam(self)
, ki vrne seznam vseh
podatkov v verižnem seznamu. Zgled:
>>> v1 = Vozel('nedelja')
>>> v2 = Vozel('sobota', v1)
>>> v3 = Vozel('petek', v2)
>>> v3.vrni_seznam()
['petek', 'sobota', 'nedelja']
class Vozel: """ Osnovni sestavni del verižnega seznama. """ def __init__(self, podatek=None, naslednji=None): self.podatek = podatek self.naslednji = naslednji def __str__(self): return str(self.podatek) def vrni_seznam(self): """ Vrni seznam s podatki, ki so shranjeni v vozlih. """ sez = [] p = self while p is not None: sez.append(p.podatek) p = p.naslednji return sez
Razredu Vozel
dodajte metodo dodaj_na_zacetek(self, x)
, ki doda nov
vozel na začetek verižnega seznama self
, ter vrne referenco na novi vozel.
Zgled:
>>> v = Vozel('nedelja')
>>> v = v.dodaj_na_zacetek('sobota')
>>> v = v.dodaj_na_zacetek('petek')
>>> v.vrni_seznam()
['petek', 'sobota', 'nedelja']
class Vozel(Vozel): def dodaj_na_zacetek(self, x): """ Dodaj nov vozel na začetek verižnega seznama. """ return Vozel(x, self)
Razredu Vozel
dodajte metodo dodaj_na_konec(self, x)
, ki doda nov
vozel na konec verižnega seznama self
. Zgled:
>>> v = Vozel('petek')
>>> v.dodaj_na_konec('sobota')
>>> v.dodaj_na_konec('nedelja')
>>> v.vrni_seznam()
['petek', 'sobota', 'nedelja']
class Vozel(Vozel): def dodaj_na_konec(self, x): """ Dodaj nov vozel na konec verižnega seznama. """ p = self while p.naslednji != None: p = p.naslednji p.naslednji = Vozel(x)
Razredu Vozel
dodajte metodo __len__(self)
, ki vrne število vozlov v
verižnem seznamu. Zgled:
>>> v = Vozel('sobota')
>>> v.dodaj_na_konec('nedelja')
>>> v = v.dodaj_na_zacetek('petek')
>>> len(v)
3
class Vozel(Vozel): def __len__(self): """ Vrni število vozlov v verižnem seznamu. """ if self.naslednji is None: return 1 return 1 + len(self.naslednji)
Dodali bomo še nekaj funkcij za delo z verižnimi seznami.
Sestavite funkcijo stevilska_veriga(a, b)
, ki vrne verižni seznam, ki
vsebuje števila od a
do b
. Funkcija naj vrne referenco na prvi vozel.
Predpostavite, da velja a <= b
. Zgled:
>>> v = stevilska_veriga(3, 7)
>>> v.vrni_seznam()
[3, 4, 5, 6, 7]
def stevilska_veriga(a, b): """ Vrni verižni seznam, ki vsebuje vsa števila od a do b. """ if a == b: return Vozel(a) return Vozel(a, stevilska_veriga(a + 1, b))
Sestavite funkcijo seznam_sodih(vozel)
, ki kot argument dobil referenco
na vozel in vrne seznam z vsemi sodimi elementi v tem verižnem seznamu.
Predpostavite lahko, da so vsi podatki cela števila. Zgled:
>>> v = stevilska_veriga(3, 11)
>>> seznam_sodih(v)
[4, 6, 8, 10]
def seznam_sodih(vozel): """ Vrni seznam vseh sodih elementov v verižnem seznamu. """ l = [] while vozel is not None: if vozel.podatek % 2 == 0: l.append(vozel.podatek) vozel = vozel.naslednji return l
Sestavite funkcijo iz_seznama(l)
, ki kor argument sprejme seznam l
ter
vrne verižni seznam, ki kot podatke vsebuje elemente seznama l
. Funkcija
naj vrne referenco na prvi vozel. Predpostavite lahko, da je seznam l
neprazen. Zgled:
>>> v = iz_seznama(['torek', 'sreda', 'četrtek', 'petek'])
>>> v.dodaj_na_konec('sobota')
>>> v.vrni_seznam()
['torek', 'sreda', 'četrtek', 'petek', 'sobota']
def iz_seznama(l): """ Vrni verižni seznam, ki bo imel kot podatke elemente seznama l. """ prvi = Vozel(l[0]) p = prvi for i in range(1, len(l)): p.naslednji = Vozel(l[i]) p = p.naslednji return prvi
Razredu Vozel
dodajte metodo zadnji_vozel(self)
, ki vrne referenco na
zadnji vozel v verižnem seznamu. Zgled:
>>> v = iz_seznama(['sreda', 'četrtek', 'petek', 'sobota'])
>>> z = v.zadnji_vozel()
>>> print(z)
'sobota'
class Vozel(Vozel): def zadnji_vozel(self): p = self while p.naslednji is not None: p = p.naslednji return p
Razredu Vozel
dodajte metodo vstavi_na_mesto(self, n, x)
, ki dobi število
n
in podatek x
. Metoda naj na n
-to mesto v verižni seznam vstavi nov
vozel s podatkom x
. Funkcija naj vrne referenco na prvi vozel v verižnem
seznamu. Če verižni seznam ni dovolj dolg, dodajte ustrezno število vozlov,
ki imajo kot podatek None
. Zgled:
>>> v = iz_seznama(['sreda', 'četrtek', 'sobota'])
>>> v = v.vstavi_na_mesto(2, 'petek')
>>> v.vrni_seznam()
['sreda', 'četrtek', 'petek', 'sobota']
class Vozel(Vozel): def vstavi_na_mesto(self, n, x): if n == 0: return self.dodaj_na_zacetek(x) if self.naslednji == None: if n == 1: self.naslednji = Vozel(x) return self else: self.naslednji = Vozel() self.naslednji = self.naslednji.vstavi_na_mesto(n - 1, x) return self
Razred Vozel
predstavlja osnovni gradnik verižnega seznama. Pri tej nalogi
bomo dodali razredu Vozel
nekaj novih metod. Za osnovno vzemite naslednjo
implementacijo:
class Vozel:
"""
Osnovni sestavni del verižnega seznama.
"""
def __init__(self, podatek=None, naslednji=None):
self.podatek = podatek
self.naslednji = naslednji
def __str__(self):
return str(self.podatek)
Dodajte še funkcijo iz_seznama
, ki ste jo sestavili pri prejšnji nalogi in
metodo vrni_seznam
. Če želite, lahko dodate še kakšno metodo oz. funkcijo.
Razredu Vozel
dodajte metodo podvoji_verigo(self)
, ki naj sestavi in
vrne novo kopijo verige, stare pa naj ne spreminja. Zgled:
>>> v = iz_seznama([2, 3, 4, 5])
>>> v2 = v.podvoji_verigo()
>>> v2.podatek = 11
>>> v.vrni_seznam()
[2, 3, 4, 5]
>>> v2.vrni_seznam()
[11, 3, 4, 5]
class Vozel: """ Osnovni sestavni del verižnega seznama. """ def __init__(self, podatek=None, naslednji=None): self.podatek = podatek self.naslednji = naslednji def __str__(self): return str(self.podatek) def vrni_seznam(self): """ Vrni seznam s podatki, ki so shranjeni v vozlih. """ sez = [] p = self while p is not None: sez.append(p.podatek) p = p.naslednji return sez def iz_seznama(l): """ Vrni verižni seznam, ki bo imel kot podatke elemente seznama l. """ if not l: # če je seznam prazen return None prvi = Vozel(l[0]) p = prvi for i in range(1, len(l)): p.naslednji = Vozel(l[i]) p = p.naslednji return prvi class Vozel(Vozel): def podvoji_verigo(self): if self.naslednji is None: return Vozel(self.podatek) return Vozel(self.podatek, self.naslednji.podvoji_verigo())
Sestavite funkcijo stakni_verigi(v1, v2)
, ki kot argumenta prejme referenci
na dva vozla in sestavi novo verigo, ki jo dobi tako, da stakne obe verigi.
To pomeni, da morata ostati verigi v1
in v2
nespremenjeni, funkcija pa
vrne povsem novo verigo! Na primer:
>>> v1 = iz_seznama([1, 2, 3])
>>> v2 = iz_seznama([4, 5, 6])
>>> v = stakni_verigi(v1, v2)
>>> v.vrni_seznam()
[1, 2, 3, 4, 5, 6]
>>> v1.vrni_seznam()
[1, 2, 3]
def stakni_verigi(v1, v2): '''Iz verig v1 in v2 naredi novo verigo. Prvotni ostaneta nespremenjeni! ''' v = v1.podvoji_verigo() # nova, podvojena veriga # postavimo se na konec nove p = v while p.naslednji is not None: p = p.naslednji # in tej verigi dodamo kopijo verige v2 p.naslednji = v2.podvoji_verigo() return v def stakni_verigi(v1, v2): ''' "Grša oblika" Iz verig v1 in v2 naredi novo verigo. Prvotni ostaneta nespremenjeni! ''' s1 = v1.vrni_seznam() s2 = v2.vrni_seznam() return iz_seznama(s1 + s2)
Sestavite funkcijo multipliciraj_verigo(v, n)
, ki kot argumenta prejme
referenco na vozel in naravno število n
ter vrne verigo spremeni, tako da
iz vsakega vozla naredi n
zaporednih kopij. Funkcija naj vrne referenco
na prvi vozel. Na primer:
>>> v = iz_seznama([7, 5, 2])
>>> v = multipliciraj_verigo(v, 3)
>>> v.vrni_seznam()
[7, 7, 7, 5, 5, 5, 2, 2, 2]
def multipliciraj_verigo(v, n, k=None): if v is None: return None if k is None: k = n if k == 1: v.naslednji = multipliciraj_verigo(v.naslednji, n) return v v2 = Vozel(v.podatek, multipliciraj_verigo(v, n, k-1)) return v2
Sestavite funkcijo na_zadrgo(v1, v2)
, ki kot argumenta prejme referenci
na dva vozla. Funkcija naj vrne verigo, ki jo dobi tako, da "na zadrgo"
združi obe verigi. Funkcija naj vrne referenco na prvi vozel tako dobljene
verige. Na primer:
>>> v1 = iz_seznama([7, 5, 2])
>>> v2 = iz_seznama([1, 3, 4, 9, 8])
>>> v = na_zadrgo(v1, v2)
>>> v.vrni_seznam()
[7, 1, 5, 3, 2, 4, 9, 8]
def na_zadrgo(v1, v2): if v1 is None: return v2 if v2 is None: return v1 v = na_zadrgo(v1.naslednji, v2.naslednji) v1.naslednji = v2 v2.naslednji = v return v1
Sestavite funkcijo odpni_zadrgo(v)
, ki kot argument prejme referenco na
vozel ter vrne dve verigi, ki jih dobi tako, da "odpne zadrgo", tj. vozle
naj razdeli med dve verigi. Funkcija naj vrne par in sicer referenci na
začetna vozla v obeh verigah. Na primer:
>>> v = iz_seznama([7, 5, 2, 1, 3, 4, 9, 8])
>>> v1, v2 = odpni_zadrgo(v)
>>> v1.vrni_seznam()
[7, 2, 3, 9]
>>> v2.vrni_seznam()
[5, 1, 4, 8]
def odpni_zadrgo(v): if v is None: return None, None vn = v.naslednji if vn is None: return v, None v1, v2 = odpni_zadrgo(v.naslednji.naslednji) v.naslednji = v1 vn.naslednji = v2 return v, vn
Sestavite funkcijo odstrani(v, x)
, ki kot argumenta prejme referenco na
vozel ter element x
. Funkcija naj verigo popravi, tako da odstrani vozle,
ki kot podatek vsebujejo element x
. Funkcija naj vrne referenco na
začetni vozel verige. Na primer:
>>> v = iz_seznama([7, 5, 2, 5, 3, 5])
>>> v = odstrani(v, 5)
>>> v.vrni_seznam()
[7, 2, 3]
def odstrani(v, x): if v is None: return None if v.podatek != x: v.naslednji = odstrani(v.naslednji, x) return v return odstrani(v.naslednji, x)
Sestavite funkcijo sodi_in_lihi(v)
, ki kot argument prejme referenco na
vozel ter vrne dve verigi, ki jih dobi tako, da v eno zloži vozle, ki vebujejo
sode podatke, v drugo pa vozle, ki vsebujejo lihe podatke. Funkcija naj vrne
par in sicer referenci na začetna vozla v obeh verigah. Na primer:
>>> v = iz_seznama([7, 5, 2, 1, 3, 4, 9, 8])
>>> v1, v2 = sodi_in_lihi(v)
>>> v1.vrni_seznam()
[2, 4, 8]
>>> v2.vrni_seznam()
[7, 5, 1, 3, 9]
def sodi_in_lihi(v): if v is None: return None, None v1, v2 = sodi_in_lihi(v.naslednji) if v.podatek % 2 == 0: v.naslednji = v1 return v, v2 v.naslednji = v2 return v1, v
Razredu Vozel
dodajte metodo je_urejen(self)
, ki vrne True
, če je
verižni seznam urejen naraščajoče in False
, če ni. Zgled:
>>> v = iz_seznama([1, 2, 4, 7, 8])
>>> v.je_urejen()
True
>>> v = iz_seznama([1, 2, 4, 3, 7])
>>> v.je_urejen()
False
class Vozel(Vozel): def je_urejen(self): if self.naslednji is None: return True if self.podatek > self.naslednji.podatek: return False return self.naslednji.je_urejen()
Razredu Vozel
dodajte metodo vstavi_v_urejenega(self, x)
, ki podatek x
vstavi na primerno mesto v verižni seznam. Predpostavka je, da je verižni
seznam urejen. Metoda naj vrne začetni vozel tega verižnega seznama. Zgled:
>>> v = iz_seznama([1, 2, 4, 7, 8])
>>> v = v.vstavi_v_urejenega(3)
>>> v.vrni_seznam()
[1, 2, 3, 4, 7, 8]
class Vozel(Vozel): def vstavi_v_urejenega(self, x): if x <= self.podatek: v = Vozel(x, self) return v if self.naslednji is None: self.naslednji = Vozel(x) else: self.naslednji = self.naslednji.vstavi_v_urejenega(x) return self
Sestavite funkcijo preuredi_parnost(v)
, ki kot argument prejme referenco na
vozel ter verižni seznam tako preuredi, da postavi vse vozle, ki vsebujejo lih
podatek na začetek, vozle, ki vsebujejo sod podatek pa na konec. Funkcija naj
vrne par in sicer referenci na začetna vozla v obeh verigah. Na primer:
>>> v = iz_seznama([7, 5, 2, 1, 3, 4, 9, 8])
>>> v = preuredi_parnost(v)
>>> v.vrni_seznam()
[7, 5, 1, 3, 9, 2, 4, 8]
def pripoji_verigo(v1, v2): p = v1 while p.naslednji is not None: p = p.naslednji p.naslednji = v2 return v1 def preuredi_parnost(v): s, l = sodi_in_lihi(v) return pripoji_verigo(l, s)
Pepi je sestavil verižni seznam in ugotovil, da je elemente nizal v seznam
v napačnem vrstnem redu. Zdaj je treba seznam obrniti, tako da obstoječih
vozlov ne brišemo in ne dodajamo novih. Sestavite funkcijo obrni_na_mestu(v)
,
ki dobi verižni seznam in ga obrne na mestu. Funkcijo mora vrniti referenco
na prvi vozel. Zgled:
>>> v = iz_seznama([7, 5, 2, 1])
>>> v = obrni_na_mestu(v)
>>> v.vrni_seznam()
[1, 2, 5, 7]
def obrni_na_mestu(v): prejsnji = None while v is not None: nasl = v.naslednji v.naslednji = prejsnji prejsnji = v v = nasl return prejsnji
Otroci se bodo igrali skrivalnice. Izbrati morajo nekoga, ki bo mižal, zato
so se vsi postavili v krog. Uporabljajo zelo popularno izštevanko, ki ima n
zlogov. Sestavite funkcijo kdo_mizi(imena, n)
, ki kot argument dobi seznam
imen in naravno število n
. Funkcija naj najprej sestavi krožni seznam (tako
kot verižni seznam, samo da zadnji element kaže na prvega). Nato vozle izločamo
iz kroga, tako da zbrišemo
>>> kdo_mizi(['Mojca', 'Janez', 'Micka', 'Peter', 'Matjaž', 'Jožefa'], 5)
'Mojca'
class Vozel: """ Osnovni sestavni del verižnega seznama. """ def __init__(self, podatek=None, naslednji=None): self.podatek = podatek self.naslednji = naslednji def __str__(self): return str(self.podatek) def vrni_seznam(self): """ Vrni seznam s podatki, ki so shranjeni v vozlih. """ sez = [] p = self while p is not None: sez.append(p.podatek) p = p.naslednji return sez def iz_seznama(l): """ Vrni verižni seznam, ki bo imel kot podatke elemente seznama l. """ prvi = Vozel(l[0]) p = prvi for i in range(1, len(l)): p.naslednji = Vozel(l[i]) p = p.naslednji return prvi def kdo_mizi(imena, n): i = 0 while len(imena) > 1: i = (i + n - 1) % len(imena) del imena[i] return imena[0]
Sestavite še funkcijo zgodovina_izstevanja(imena, n)
, ki naj deluje podobno
kot funkcija iz prve podnaloge, le da vrne seznam, ki vsebuje imena v takem
vrstnem redu, kot smo jih izločali pri izštevanki. Zgled:
>>> zgodovina_izstevanja(['Mojca', 'Janez', 'Micka', 'Peter', 'Matjaž', 'Jožefa'], 5)
['Matjaž', 'Peter', 'Jožefa', 'Janez', 'Micka', 'Mojca']
def zgodovina_izstevanja(imena, n): i = 0 ret = [] while len(imena) > 0: i = (i + n - 1) % len(imena) ret.append(imena[i]) del imena[i] return ret
Zdaj pa sestavite še funkcijo odhajanje_iz_kroga(imena, n)
, ki deluje podobno
kot prejšnja funkcija, le da vrne verižni seznam namesto običajnega seznama.
Vozli naj bodo urejeni tako, da je v zadnjem vozlu shranjeno ime otroka, ki je
najprej zapustil krog. Zgled:
>>> v = odhajanje_iz_kroga(['Mojca', 'Janez', 'Micka', 'Peter', 'Matjaž', 'Jožefa'], 5)
>>> v.vrni_seznam()
['Mojca', 'Micka', 'Janez', 'Jožefa', 'Peter', 'Matjaž']
def odhajanje_iz_kroga(imena, n): i = 0 ret = [] while len(imena) > 0: i = (i + n - 1) % len(imena) ret.append(imena[i]) del imena[i] return iz_seznama(ret[::-1])
Vaš stari znanec Jože goji zajce. Zajci so se v zadnjih letih tako namnožili, da si Jože enostavno ne more več zapomniti vseh. Zato potrebuje primeren informacijski sistem. V pomoč mu sestavite razred, ki bo vseboval vse potrebne podatke o resničnem zajcu.
Sestavite razred Zajec
s konstruktorjem __init__(self, teza, starost)
,
ki predstavlja zajca z dano težo in starostjo. Vrednosti shranite v
atributa z imenoma teza
in starost
.
class Zajec: def __init__(self, teza, starost): self.teza = teza self.starost = starost
Sestavite metodo nahrani(self, hrana)
, kjer je argument hrana
teža
hrane, ki jo damo zajcu. Pri hranjenju se teža zajca poveča za 30 %
teže hrane, ki jo zajec poje. Zgled:
>>> z = Zajec(5, 2)
>>> z.nahrani(2)
>>> z.teza
5.6
class Zajec(Zajec): def nahrani(self, hrana): self.teza += hrana * 0.3
Sestavite metodo __str__(self)
, ki vrne predstavitev razreda Zajec
z nizom oblike 'Zajec težak X kg, star Y let.'
.
Primer:
>>> z = Zajec(5, 2)
>>> print(z)
'Zajec težak 5 kg, star 2 let.'
Opomba: Funkcija print
na svojem argumentu pokliče metodo __str__
in izpiše niz, ki ga ta metoda vrne. Metoda __str__
običajno vrne
razumljiv opis objekta, ki naj bi ga razumeli tudi ne-programerji.
class Zajec(Zajec): def __str__(self): return "Zajec težak {1} kg, star {0} let.".format(self.starost, self.teza)
Sestavite še metodo __repr__(self)
, ki vrne predstavitev razreda
Zajec
kot niz oblike 'Zajec(X, Y)'
, kjer je X
teža, Y
pa starost
zajca.
Primer:
>>> z = Zajec(5, 2)
>>> z
Zajec(5, 2)
Opomba: Če v interaktivni konzoli pokličemo nek objekt, se izpiše niz,
ki ga vrne klic metode __repr__
na tem objektu. Priporočilo je, da je
niz, ki ga vrne metoda __repr__
, veljavna programska koda v Pythonu, ki
ustvari identično kopijo objekta.
class Zajec(Zajec): def __repr__(self): return 'Zajec({1}, {0})'.format(self.starost, self.teza)
Sestavite metodo __lt__(self, drugi)
, ki dva zajca primerja med sabo.
Metoda naj vrne True
, če je prvi zajec manjši od drugega in False
sicer.
Manjši zajec je tisti, ki je lažji. Če pa imata zajca enako maso, je manjši tisti, ki je mlajši (tj. ima manjše število let).
>>> Zajec(5, 3) < Zajec(6, 2)
True
>>> Zajec(3, 1) < Zajec(2, 2)
False
>>> Zajec(4, 3) < Zajec(4, 2)
False
class Zajec(Zajec): def __lt__(self, drugi): if self.teza < drugi.teza: return True if self.teza == drugi.teza and self.starost < drugi.starost: return True return False
Sestavite funkcijo uredi(teze, starosti)
. Argumenta teze
in starosti
sta enako dolga seznama števil, kjer uredi
naj ne bo znotraj razreda Zajec
,
saj ni objektna metoda, ampak je čisto običajna funkcija.
Funkcija naj ustvari seznam ustreznih primerkov razreda Zajec
, ga uredi
po velikosti glede na zgoraj opisano relacijo in ta seznam vrne kot rezultat.
>>> l = uredi([5, 4, 4], [3, 2, 3])
>>> for z in l:
... print(z)
...
Zajec težak 4 kg, star 2 let.
Zajec težak 4 kg, star 3 let.
Zajec težak 5 kg, star 3 let.
def uredi(teze, starosti): zajci = [Zajec(teze[i], starosti[i]) for i in range(len(teze))] zajci.sort() return zajci
Pri tej vaji bomo implementirali razrede Vektor
, Tocka
in Premica
,
ki predstavljajo vektor, točko in premico v evklidski ravnini. Nekaj
metod je že implementiranih, nekaj pa jih boste implementirali sami.
Najprej si oglejte naslednjo kodo. To potem tudi skopirajte na začetek prve naloge!
import math
EPS = 1e-12
def eq(a, b, eps=EPS): # Pomožna funkcija
''' se a in b razlikujeta za manj kot EPS'''
return abs(a - b) < eps
class Vektor:
"""
Vektor v ravnini.
"""
def __init__(self, x, y):
self.x = x
self.y = y
def __eq__(self, other):
"""
Vrni True, če sta vektorja enaka.
"""
return eq(self.x, other.x) and eq(self.y, other.y)
def __add__(self, other):
"""
Vrni vsoto vektorjev self in other.
"""
return Vektor(self.x + other.x, self.y + other.y)
def skalarni_produkt(self, other):
"""
Vrni standardni skalarni produkt vektorjev self in other.
"""
return self.x * other.x + self.y * other.y
def __mul__(self, other):
"""
Vrni skalarni produkt vektorjev self in other, če je other tudi vektor.
Sicer vrni produkt vektorja self s skalarjem other (če je other skalar).
"""
if type(other) == Vektor:
return self.skalarni_produkt(other)
else:
return Vektor(self.x * other, self.y * other)
def normiran(self):
"""
Vrni normiran vektor.
"""
return self / abs(self)
class Tocka:
"""
Točka v ravnini.
"""
def __init__(self, x, y):
self.x = x
self.y = y
def __repr__(self):
return 'Tocka({0}, {1})'.format(self.x, self.y)
def __str__(self):
return '({0}, {1})'.format(self.x, self.y)
def __eq__(self, other):
"""
Vrni True, če sta vektorja enaka.
"""
return eq(self.x, other.x) and eq(self.y, other.y)
def __sub__(self, other):
"""
Vrni vektor od točke other do točke self.
"""
return Vektor(self.x - other.x, self.y - other.y)
def translacija(self, v):
"""
Vrni translacijo točke self za vektor v.
"""
return Tocka(self.x + v.x, self.y + v.y)
def __add__(self, v):
"""
Vrni translacijo točke self za vektor v.
"""
return self.translacija(v)
def razdalja_do(self, other):
"""
Vrni razdaljo točke self do objekta other. Objekt other je lahko Tocka ali Premica.
"""
if type(other) == Tocka:
return abs(self - other)
elif type(other) == Premica:
return abs(other.predznacena_razdalja(self))
else:
raise TypeError("nepodprta operacija za tipa: '{0}' in '{1}'".format(type(self), type(other)))
class Premica:
"""
Premica v ravnini.
Premico predstavimo s točko in normalo.
"""
def __init__(self, tocka, normala):
self.tocka = tocka
self.normala = normala
def __repr__(self):
return 'Premica({0}, {1})'.format(self.tocka, self.normala)
def enacba(self):
"""
Vrne koeficiente a, b in c za enačbo premice :math:`a x + b y = c`.
"""
a, b = self.normala.x, self.normala.y
c = self.normala.skalarni_produkt(self.tocka)
return a, b, c
def __str__(self):
a, b, c = self.enacba()
return '{0} x + {1} y = {2}'.format(a, b, c)
def smernik(self):
"""
Vrni vektor, ki leži na premici self.
"""
a, b = self.normala.x, self.normala.y
return Vektor(-b, a)
def pravokotnica(self, tocka=None):
tocka = tocka or self.tocka
# Prejšnja vrstica je ekvivalentna tejle: if tocka is None: tocka = self.tocka
return Premica(tocka, self.smernik())
def predznacena_razdalja(self, tocka):
"""
Vrni predznačeno razdaljo od točke tocka do premice self.
"""
return self.normala.normiran() * (tocka - self.tocka)
Razredu Vektor
dodajte metodo __repr__(self)
. Zgled:
>>> v = Vektor(3, 2)
>>> v
Vektor(3, 2)
Opomba: Če v interaktivni konzoli pokličemo nek objekt, se izpiše niz,
ki ga vrne klic metode __repr__
na tem objektu. Priporočilo je, da je
niz, ki ga vrne metoda __repr__
, veljavna programska koda v Pythonu,
ki ustvari identično kopijo objekta.
import math # Konstante EPS = 1e-12 # Pomožne funkcije def eq(a, b, eps=EPS): return abs(a - b) < eps class Vektor: """ Vektor v ravnini. """ def __init__(self, x, y): self.x = x self.y = y def __eq__(self, other): """ Vrni True, če sta vektorja enaka. """ return eq(self.x, other.x) and eq(self.y, other.y) def __add__(self, other): """ Vrni vsoto vektorjev self in other. """ return Vektor(self.x + other.x, self.y + other.y) def skalarni_produkt(self, other): """ Vrni standardni skalarni produkt vektorjev self in other. """ return self.x * other.x + self.y * other.y def __mul__(self, other): """ Vrni skalarni produkt vektorjev self in other, če je other tudi vektor. Sicer vrni produkt vektorja self s skalarjem other (če je other skalar). """ if type(other) == Vektor: return self.skalarni_produkt(other) else: return Vektor(self.x * other, self.y * other) def normiran(self): """ Vrni normiran vektor. """ return self / abs(self) class Tocka: """ Točka v ravnini. """ def __init__(self, x, y): self.x = x self.y = y def __repr__(self): return 'Tocka({0}, {1})'.format(self.x, self.y) def __str__(self): return '({0}, {1})'.format(self.x, self.y) def __eq__(self, other): """ Vrni True, če sta vektorja enaka. """ return eq(self.x, other.x) and eq(self.y, other.y) def __sub__(self, other): """ Vrni vektor od točke other do točke self. """ return Vektor(self.x - other.x, self.y - other.y) def translacija(self, v): """ Vrni translacijo točke self za vektor v. """ return Tocka(self.x + v.x, self.y + v.y) def __add__(self, v): """ Vrni translacijo točke self za vektor v. """ return self.translacija(v) def razdalja_do(self, other): """ Vrni razdaljo točke self do objekta other. Objekt other je lahko Tocka ali Premica. """ if type(other) == Tocka: return abs(self - other) elif type(other) == Premica: return abs(other.predznacena_razdalja(self)) else: raise TypeError("nepodprta operacija za tipa: '{0}' in '{1}'".format(type(self), type(other))) class Premica: """ Premica v ravnini. Premico predstavimo s točko in normalo. """ def __init__(self, tocka, normala): self.tocka = tocka self.normala = normala def __repr__(self): return 'Premica({0}, {1})'.format(self.tocka, self.normala) def enacba(self): """ Vrne koeficiente a, b in c za enačbo premice :math:`a x + b y = c`. """ a, b = self.normala.x, self.normala.y c = self.normala.skalarni_produkt(self.tocka) return a, b, c def __str__(self): a, b, c = self.enacba() return '{0} x + {1} y = {2}'.format(a, b, c) def smernik(self): """ Vrni vektor, ki leži na premici self. """ a, b = self.normala.x, self.normala.y return Vektor(-b, a) def pravokotnica(self, tocka=None): tocka = tocka or self.tocka # Prejšnja vrstica je ekvivalentna tejle: if tocka is None: tocka = self.tocka return Premica(tocka, self.smernik()) def predznacena_razdalja(self, tocka): """ Vrni predznačeno razdaljo od točke tocka do premice self. """ return self.normala.normiran() * (tocka - self.tocka) class Vektor(Vektor): def __repr__(self): return 'Vektor({0}, {1})'.format(self.x, self.y)
Razredu Vektor
dodajte metodo __str__(self)
. Zgled:
>>> v = Vektor(3, 2)
>>> print(v)
(3, 2)
Opomba: Funkcija print
na svojem argumentu pokliče metodo __str__
in izpiše niz, ki ga ta metoda vrne. Metoda __str__
običajno vrne
razumljiv opis objekta, ki naj bi ga razumeli tudi ne-programerji.
class Vektor(Vektor): def __str__(self): return '({0}, {1})'.format(self.x, self.y)
Razredu Vektor
dodajte metodo __abs__(self)
, ki naj vrne dolžino
(normo) vektorja. Zgled:
>>> v = Vektor(1, 3)
>>> abs(v)
3.1622776601683795
class Vektor(Vektor): def __abs__(self): """ Vrni dolžino vektorja self. """ return (self.x ** 2 + self.y ** 2) ** 0.5
Razredu Vektor
dodajte metodo __sub__(self, other)
, ki vrne
razliko vektorjev. Zgled:
>>> v = Vektor(-1, 3)
>>> u = Vektor(2, 1)
>>> u - v
Vektor(-3, 2)
class Vektor(Vektor): def __sub__(self, other): """ Vrni razliko vektorjev self in other. """ return Vektor(self.x - other.x, self.y - other.y)
V razredu Vektor
sestavite metodo __truediv__(self, skalar)
, ki vrne
produkt vektorja self
s skalarjem 1 / skalar
. Zgled:
>>> Vektor(-1, 3) / 2
Vektor(-0.5, 1.5)
class Vektor(Vektor): def __truediv__(self, skalar): """ Vrni produkt vektorja self s skalarjem 1/skalar. """ return self * (1 / skalar)
V razredu Vektor
sestavite metodo sta_pravokotna(self, other)
, ki
vrne True
, če sta vektorja self
in other
pravokotna, in False
sicer. Zgled:
>>> v = Vektor(-1, 3)
>>> u = Vektor(2, 1)
>>> v.sta_pravokotna(u)
False
class Vektor(Vektor): def sta_pravokotna(self, other): """ Vrni True, če sta vektorja self in other pravokotna, in False sicer. """ return eq(self.skalarni_produkt(other), 0)
V razredu Vektor
sestavite metodo rotacija(self, alpha)
, ki vrne
rotacijo vektorja self
za kot alpha
(v radianih). Zgled:
>>> Vektor(1, 0).rotacija(math.pi/4)
Vektor(0.7071067811865476, 0.7071067811865475)
class Vektor(Vektor): def rotacija(self, alpha): """ Vrni rotacijo vektorja self za kot alpha (podan v radianih). """ return Vektor(self.x * math.cos(alpha) - self.y * math.sin(alpha), self.x * math.sin(alpha) + self.y * math.cos(alpha))
Razredu Premica
dodajte metodo projekcija(self, tocka)
, ki vrne
pravokotno projekcijo točke tocka
na premico self
. Zgled:
>>> p = Premica(Tocka(1, 1), Vektor(0, 1))
>>> p.projekcija(Tocka(3, 0))
Tocka(3, 1)
class Premica(Premica): def projekcija(self, tocka): """ Vrni pravokotno projekcijo točke tocka na premico self. """ s = self.smernik() v = tocka - self.tocka w = s * (s * v) / (s * s) return self.tocka.translacija(w)
Razredu Premica
dodajte metodo presek(self, other)
, ki vrne
točko, ki je presek dveh premic. Zgled:
>>> p = Premica(Tocka(3, 4), Vektor(2, -1))
>>> q = Premica(Tocka(0, 1), Vektor(1, 2))
>>> p.presek(q)
Tocka(1.2, 0.4)
class Premica(Premica): def presek(self, other): """ Vrni presek premic self in other. """ a1, b1 = self.normala.x, self.normala.y a2, b2 = other.normala.x, other.normala.y x1, y1 = self.tocka.x, self.tocka.y x2, y2 = other.tocka.x, other.tocka.y c = a1 * b2 - a2 * b1 x = (b1 * b2 * (y1 - y2) + a1 * b2 * x1 - a2 * b1 * x2) / c y = (a1 * a2 * (x2 - x1) - a2 * b1 * y1 + a1 * b2 * y2) / c return Tocka(x, y)
Razredu Tocka
dodajte metodo zrcali_cez_premico(self, premica)
,
ki vrne zrcalno sliko točke self
čez premico premica
. Zgled:
>>> p = Premica(Tocka(1, 1), Vektor(0, 1))
>>> Tocka(3, 4).zrcali_cez_premico(p)
Tocka(3, -2)
class Tocka(Tocka): def zrcali_cez_premico(self, premica): """ Vrni točko, ki jo dobimo z zrcaljenjem točke self čez premico premica. """ n = premica.normala v = self - premica.tocka w = n * (n * v) / (n * n) return self.translacija(w * -2)
Najbolj popularnih zapisov permutacije je po mnenju mnogih ciklični zapis (tj. permutacijo zapišemo kot produkt disjunktnih ciklov). Primer:
(1 5 2) (3 6) (4)
Ciklov dolžine 1 (fiksnih točk) po navadi ne pišemo, torej zgornjo permutacijo običajno pišemo kar takole:
(1 5 2) (3 6)
Sestavite razred Permutacija
, s katerim predstavimo permutacijo.
Najprej sestavite konstruktor __init__(self, cikli, stopnja=None)
, kjer
je cikli
seznam seznamov, ki predstavljajo cikle permutacije. Argument
stopnja
ima privzeto vrednost None
– v tem primeru naj bo stopnja
največje število, ki nastopa v katerem od ciklov. Razred naj ima atributa
stopnja
in cikli
. Na prvem mestu v vsakem ciklu naj bo najmanjši
element tega cikla (s cikličnim pomikom dobimo isti cikel). Tudi cikli
naj bodo urejeni. Morebitne cikle dožine 1 naj konstruktor odstrani.
>>> p = Permutacija([[7, 3], [4], [5, 2, 1]], stopnja=7)
>>> p.stopnja
7
>>> p.cikli
[[1, 5, 2], [3, 7]]
class Permutacija: def __init__(self, cikli, stopnja=None): if stopnja is None: self.stopnja = max(map(max, cikli)) else: self.stopnja = stopnja self.cikli = [list(cikel) for cikel in cikli if len(cikel) > 1] for k in range(len(self.cikli)): cikel = self.cikli[k] # najdi najmanjsi element m = 0 for i in range(len(cikel)): if cikel[i] < cikel[m]: m = i self.cikli[k] = cikel[m:] + cikel[:m] self.cikli.sort()
V razredu Permutacija
definirajte metodo inverz(self)
, ki sestavi
in vrne inverz dane permutacije. Inverz permutacije dobimo tako, da
v cikličnem zapisu obrnemo vse cikle (vsakega posebej).
>>> p = Permutacija([[7, 3], [4], [5, 2, 1]], stopnja=7)
>>> q = p.inverz()
>>> q.stopnja
7
>>> q.cikli
[[1, 2, 5], [3, 7]]
class Permutacija(Permutacija): def inverz(self): return Permutacija([c[::-1] for c in self.cikli], stopnja=self.stopnja)
V razredu Permutacija
sestavite metodo ciklicni_tip(self)
, ki vrne
ciklični tip permutacije. To je nabor, ki ima toliko elementov, kot je
dolžina najdaljšega cikla. Prvi element v tem naboru je število ciklov
dolžine 1, drugi element je število ciklov dolžine 2, itn.
>>> p = Permutacija([[7, 3], [4], [5, 2, 1]], stopnja=7)
>>> p.ciklicni_tip()
(2, 1, 1)
class Permutacija(Permutacija): def ciklicni_tip(self): dolzine = [len(c) for c in self.cikli] najdaljsi_cikel = max(dolzine) ctip = [dolzine.count(i) for i in range(1, najdaljsi_cikel + 1)] ctip[0] = self.stopnja - sum(dolzine) return tuple(ctip)
V razredu Permutacija
sestavite metodo red(self)
, ki izračuna in
vrne red permutacije. Naj bo
Namig 1: Red permutacije je najmanjši skupni večkratnik dolžin vseh ciklov.
Namig 2: Za poljubni dve naravni števili a
in b
velja, da je
gcd(a, b) * lcm(a, b) == a * b
. (Funkcija gcd
računa največji
skupni delitelj, funkcija lcm
pa najmanjši skupni večkratnik.)
>>> p = Permutacija([[7, 3], [4], [5, 2, 1]], stopnja=7)
>>> p.red()
6
def gcd(a, b): while b != 0: a, b = b, a % b return a def lcm(a, b): return a * b // gcd(a, b) class Permutacija(Permutacija): def red(self): r = 1 for c in self.cikli: r = lcm(r, len(c)) return r
Naj bo NeusmerjenGraf
za delo z enostavnimi (ni zank in ni vzporednih
povezav) neusmerjenimi grafi.
Najprej sestavite konstruktor __init__(self, seznam_povezav)
, ki
sprejme seznam parov seznam_povezav
(vsak par predstavlja eno
povezavo). Konstruktor naj objektu pripne atribut sosedje
, ki naj bo
slovar, katerega ključi so oznake vozlišč, vrednost ključa pa je množica
sosedov te točke. Zgled:
>>> g = NeusmerjenGraf([(1, 2), (2, 3), (3, 1), (1, 4)])
>>> g.sosedje
{1: {2, 3, 4}, 2: {1, 3}, 3: {1, 2}, 4: {1}}
class NeusmerjenGraf: def __init__(self, seznam_povezav): self.sosedje = dict() for u, v in seznam_povezav: if u not in self.sosedje: self.sosedje[u] = set() self.sosedje[u].add(v) if v not in self.sosedje: self.sosedje[v] = set() self.sosedje[v].add(u)
Sestavite metodo slovar_stopenj(self)
, ki vrne slovar, katerega ključi
so oznake vozlišč, vrednosti pa so njihove stopnje. Zgled:
>>> g = NeusmerjenGraf([(1, 2), (2, 3), (3, 1), (1, 4)])
>>> g.slovar_stopenj()
{1: 3, 2: 2, 3: 2, 4: 1}
class NeusmerjenGraf(NeusmerjenGraf): def slovar_stopenj(self): return {k: len(v) for k, v in self.sosedje.items()}
Sestavite metodo dodaj_vozlisce(self, u)
, ki v graf doda vozlišče z
oznako u
. Če vozlišče s to oznako že obstaja, naj metoda ne naredi
ničesar. Zgled:
>>> g = NeusmerjenGraf([(1, 2), (2, 3), (3, 1)])
>>> g.dodaj_vozlisce(4)
>>> g.sosedje
{1: {2, 3}, 2: {1, 3}, 3: {1, 2}, 4: set()}}
class NeusmerjenGraf(NeusmerjenGraf): def dodaj_vozlisce(self, u): if u not in self.sosedje: self.sosedje[u] = set()
Sestavite metodo odstrani_vozlisce(self, u)
, ki iz grafa odstrani
vozlišče z oznako u
in vse povezave, ki imajo u
za krajišče. Ppredpostavi,
da je vozlišča u
zagotovo v grafu. Zgled:
>>> g = NeusmerjenGraf([(1, 2), (2, 3), (3, 1)])
>>> g.odstrani_vozlisce(3)
>>> g.sosedje
{1: {2}, 2: {1}}
class NeusmerjenGraf(NeusmerjenGraf): def odstrani_vozlisce(self, u): del self.sosedje[u] for mn_sos in self.sosedje.values(): mn_sos.discard(u)
Sestavite metodo dodaj_povezavo(self, e)
, ki v graf doda povezavo e
(par vozlišč). Če ta povezava že obstaja, naj metoda ne naredi ničesar.
V primeru, če katero od krajišč povezave manjka, še njega dodajte v
graf (s klicem metode dodaj_vozlisce
). Zgled:
>>> g = NeusmerjenGraf([(1, 2), (2, 3), (3, 1)])
>>> g.dodaj_povezavo((1, 4))
>>> g.sosedje
{1: {2, 3, 4}, 2: {1, 3}, 3: {1, 2}, 4: {1}}
class NeusmerjenGraf(NeusmerjenGraf): def dodaj_povezavo(self, e): u, v = e self.dodaj_vozlisce(u) self.dodaj_vozlisce(v) self.sosedje[u].add(v) self.sosedje[v].add(u)
Sestavite še metodo odstrani_povezavo(self, e)
, ki iz grafa odstrani
povezavo e
(par vozlišč). Predpostavi, da je povezava e
zagotovo v grafu.
Zgled:
>>> g = NeusmerjenGraf([(1, 2), (2, 3), (3, 1)])
>>> g.odstrani_povezavo((1, 2))
>>> g.sosedje
{1: {3}, 2: {3}, 3: {1, 2}}
class NeusmerjenGraf(NeusmerjenGraf): def odstrani_povezavo(self, e): u, v = e self.sosedje[u].remove(v) self.sosedje[v].remove(u)