Rešitev
Odstrani enake
Napiši funkcijo odstrani_enake(s, t)
, ki prejme dva enako dolga seznama. Funkcija primerja istoležne pare njunih elementov in če sta oba elementa enaka, ju pobriše iz seznamov. Funkcija ne vrača ničesar, temveč spreminja prejeta seznama. V spodnjem primeru pobriše pare 3, 2 in 4.
>>> a = [1, 3, 2, 13, 2, 4, 4]
>>> b = [8, 3, 13, 8, 2, 4, 5]
>>> odstrani_enake(a, b)
>>> a
[1, 2, 13, 4]
>>> b
[8, 13, 8, 5]
Rešitev
Tole je klasičen vzorec brisanje po seznamih: uporabiti je potrebno zanko while
. Če poskusimo kaj v slogu
for e in s:
if potrebno_pobrisati(e):
s.remove(e)
to ne bo nujno pobrisalo te pojavitve e
-ja temveč prvo, na katero remove
naleti. Poleg tega pa bo zanka for
preskočila element, ki sledi e
-ju in je prišel na e
-jevo mesto.
Tudi
for i, e in enumerate(s):
if potrebno_pobrisati(e):
del s[i]
ne deluje. Pobriše sicer pravi, i
-ti element seznama, vendar se element z indeksom i + 1
pri tem prestavi na i
-to mesto in se izmakne zanki.
Pravi vzorec je torej
i = 0
while i < len(s):
if potrebno_pobrisati(s[i]):
del s[i]
else:
i += 1
Druga, prav tako legalna možnost je sestavljanje novega seznama, vendar moramo v tem primeru paziti, kako zamenjamo elemente obstoječega seznama z novimi:
t = []
for e in s:
if not potrebno_pobrisati(e):
t.append(e)
s[:] = t
Če bi v zadnji vrstici napisali s = t
, bi ostala vsebina seznama, ki smo ga v začetku imenovali s
(in ki je bil podan kot argument funkciji) nespremenjena.
Zdaj pa končno rešimo nalogo.
def odstrani_enake(s, t):
i = 0
while i < len(s):
if s[i] == t[i]:
del s[i]
del t[i]
else:
i += 1
Zelo podobno nalogo so imeli tudi v prvi skupini. Njihova je bila nekoliko težja ... zato pa je bila v drugi skupini nekoliko težja tretja naloga.
Diff
Napiši funkcijo diff(datoteka1, datoteka2)
, ki prejme imeni dveh datotek in vrne seznam razlik med njima. Vrnjeni seznam naj vsebuje trojke (številka vrstice, niz z vrstico iz prve datoteke, niz z vrstico iz druge datoteke). Datoteki vsebujeta enako število vrstic. Prva vrstica naj ima številko 1. Vrsticam odstrani znake za novo vrstico.
Recimo, da imamo datoteki
Ana
Berta
Cecilija
Dani
Ema
in
Ana
Berta
Cilka
Dani
Eva Ema
Funkcija vrne [(3, 'Cecilija', 'Cilka'), (5, 'Ema', 'Eva Ema')]
.
Rešitev
Tole je očitno naloga iz branja datotek, pri ocenjevanju pa sem upošteval tudi spretnost programiranja, uporabo zip
in tako naprej.
Najhitreje gre tako:
def diff(dat1, dat2):
razlike = []
for i, (vrstica1, vrstica2) in enumerate(zip(open(dat1), open(dat2)), start=1):
if vrstica1 != vrstica2:
razlike.append((i, vrstica1.strip(), vrstica2.strip()))
return razlike
Magija je seveda v zanki. Odpremo obe datoteki: open(dat1)
, open(dat2)
. Namesto da bi šli prek njiju z ločenima zankama, ju zadrgnemo skupaj: zip(open(dat1), open(dat2))
. Vendar bomo potrebovali še zaporedne številke, zato enumerate(zip(open(dat1), open(dat2)))
. enumerate
začne šteti z 0
. Nič hudega, v append
-u bi pač pisali i + 1
. Lahko pa dodamo še argument start=1
, pa bo štel od 1.
Zdaj pa se ozrimo še levo od in
. Tam piše i, (vrstica1, vrstica2)
. To je potrebno zato, ker smo z zip
sestavili pare, nato pa jih z enumerate
oštevilčili. Če bi pisali for i, vrstica1, vrstica2
, to ne bi delovalo, saj nam enumerate(zip(...))
ne sestavi trojk temveč pare, v kateri je drugi element spet par.
Mesta
Imamo seznam, ki vsebuje imema tekmovalcev in število točk, ki so jih dosegli, npr. [("Ana", 15), ("Berta", 13), ("Cilka", 12), ("Dani", 12), ("Ema", 8), ("Fanči", 6), ("Greta", 6)]
. Seznam je že urejen po padajočem številu točk. Točke so nenegativna cela števila.
Napiši funkcijo mesta(s)
, ki prejme takšen seznam in vrne takšen seznam, v katerem bo i-ti element vseboval seznam vseh, ki so uvrščeni na i-to mesto. Za gornji primer vrne [["Ana"], ["Berta"], ["Cilka", "Dani"], [], ["Ema"], ["Fanči", "Greta"], []]
. Cilka in Dani sta v istem seznamu, ker si delita tretje mesto in četrti seznam je prazen, ker nihče ni četrti. Podobno je z Fanči in Greto: sta v istem seznamu in naslednji seznam je prazen. Isto mesto si lahko deli tudi več oseb – celo vse. Za nekaj primerov poglej (tudi) teste.
Rešitev
Tole pa je naloga iz iznajdljivosti.
Sam sem jo rešil tako:
def mesta(s):
mesta = []
zadnji = None
zadnje_tocke = -1
for ime, tocke in s:
if tocke != zadnje_tocke:
zadnji = [ime]
mesta.append(zadnji)
zadnje_tocke = tocke
else:
zadnji.append(ime)
mesta.append([])
return mesta
V zadnje_tocke
si zapomnim, koliko točk je imel zadnji, ki sem ga dodal v seznam, v zadnji
pa zadnji seznam, v katerega sem koga dodal. mesta
je seznam, ki ga sestavljam. Znotraj zanke v vsakem koraku zagotovo nekaj dodam v mesta
. Če je število točk trenutnega tekmovalca različno od točk prejšnjega, sestavimo nov zadnji
seznam, v njem je to ime, in ta seznam gre v mesta
. Če je število točk enako, pa dodam v mesta
prazen seznam, tole ime pa gre v zadnji
.
Večina študentov, ki je uspela rešiti to nalogo, se je izmazala s slovarji. Recimo tako:
from collections import defaultdict
def mesta(s):
po_tockah = defaultdict(list)
for oseba, tocke in s:
po_tockah[tocke].append(oseba)
mesta = []
for tocke in sorted(po_tockah, reverse=True):
na_mestu = po_tockah[tocke]
mesta.append(na_mestu)
mesta += [[]] * (len(na_mestu) - 1)
return mesta
V prvem delu grupiramo tekmovalce v slovar, katerega ključi so števila točk, vrednosti pa imena tekmovalcev s takšnim številom točk. Nato gremo po vrsti po različnih številih točk. V končni seznam vsakič dodamo seznam tekmovalcev nato pa še ustrezno število praznih seznamov. (Pozorni študent bo opazil, da so vsi ti prazni seznami isti. Tule bi to moralo biti vseeno, saj vanje ne bomo ničesar dodajali.)
Dovolj lihih
Napiši rekurzivno funkcijo dovolj_lihih(s, n)
, ki vrne True
, če je v seznamu s
vsaj n
lihih števil in False
, če jih ni toliko.
(Rekurzivna naj bo prav ta funkcija s prav temi argumenti. Ne piši pomožnih funkcij.)
Rešitev
Če je prvo število liho, mora biti v ostanku seznama vsaj še n - 1
lihih števil. Sicer pa jih mora biti še n
. Torej
def dovolj_lihih(s, n):
if n == 0:
return True
if not s:
return False
if s[0] % 2 == 1:
return dovolj_lihih(s[1:], n - 1)
else:
return dovolj_lihih(s[1:], n)
Potem opazimo, da lahko združimo zadnji vrstici v eno.
def dovolj_lihih(s, n):
if n == 0:
return True
if not s:
return False
return dovolj_lihih(s[1:], n - s[0] % 2)
Ali pa združimo kar vse pogoje.
def dovolj_lihih(s, n):
return n == 0 or s and dovolj_lihih(s[1:], n - s[0] % 2)
Parkirišče
Napiši razred Parkirisce, obdarjen z naslednjimi metodami.
- Konstruktor prejme število parkirnih mest na parkirišču.
prosto()
vrneTrue
, če je na parkirišču kaj prostih mest inFalse
, če jih ni.parkiraj(registracija, cas)
pokličemo, ko ob podanem času na parkirišče pripelje avto s podano registracijo. Če je parkirišče polno, metoda ne naredi ničesar, sicer pa zabeleži, kar je potrebno za delovanje ostalih metod. Metoda ne vrne ničesar.odpelji(registracija, cas)
pokličemo, če avto s podano registracijo ob podanem času zapusti parkirišče. Metoda vrne ceno parkirnine; ta znaša toliko evrov, kolikor je začetih ur: če je avto parkiran 2.45 ure, plača 3 evre. (V modulu math se nahaja potencialno uporabna funkcija ceil.) Predpostaviti smeš, da je avto, ki je odpeljal s parkirišča, dejansko bil parkiran na parkirišču.zasluzek()
vrne vsoto vseh parkirnin za avte, ki so že zapustili parkirišče.
Časi po podani v urah. Če avto pripelje ob 10 uri in 45 minut, je argument cas enak 10.75 (10 in tri četrt). (To je preprosto: minute naj te ne vznemirjajo, za izračun parkirnine pa čase parkiranja le zaokrožaš navzgor.)
Rešitev
Konstruktor si bo očitno moral zapomniti število parkirnih mest in pripraviti slovar, katerega ključi bodo registracije, vrednosti pa časi parkiranja (saj bomo v tem slovarju kasneje iskali po registracijah). Poleg tega bo potrebno shranjevati vsoto pobranih parkirnin.
Ko se odločimo glede tega, so metode preproste.
class Parkirisce:
def __init__(self, kapaciteta):
self.kapaciteta = kapaciteta
self.parkirani = {}
self.parkirnine = 0
def prosto(self):
return len(self.parkirani) < self.kapaciteta
def parkiraj(self, registracija, cas):
if self.prosto():
self.parkirani[registracija] = cas
def odpelji(self, registracija, cas):
cena = int(math.ceil(cas - self.parkirani.pop(registracija)))
self.parkirnine += cena
return cena
def zasluzek(self):
return self.parkirnine
Zelo me je žalostilo, da večina študentov še vedno piše:
def prosto(self):
if len(self.parkirani) < self.kapaciteta:
return True
else:
return False
Vsi bodo dosegli svoj cilj, samo jaz ga ne bom dosegel, je rekel kolega Srečko.