Napiši razred Rezalnik
, katerega osnovna funkcija je, da
ima metodo razrezi(s)
, ki razreže podani seznam
s
na sezname določene dolžine. Privzeta dolžina je
2
, lahko pa jo spremenimo z metodo
nastavi_dolzino(dolzina)
.
>>> s = ["Ana", "Berta", "Cilka", "Donald", "Ema", "Fanči", "Greta", "Helga", "Iva"]
>>>
>>> r = Rezalnik()
>>> r.razrezi(s)
[['Ana', 'Berta'],
['Cilka', 'Donald'],
['Ema', 'Fanči'],
['Greta', 'Helga'],
['Iva']]
>>>
>>> r.nastavi_dolzino(4)
>>> r.razrezi(s)
[['Ana', 'Berta', 'Cilka', 'Donald'],
['Ema', 'Fanči', 'Greta', 'Helga'],
['Iva']]
>>>
>>> r.nastavi_dolzino(3)
>>> r.razrezi(s)
[['Ana', 'Berta', 'Cilka'],
['Donald', 'Ema', 'Fanči'],
['Greta', 'Helga', 'Iva']]
Razred naj ima torej metode:
__init__
, ki dela, kar mora,razrezi
, ki prejme nek seznam s
in vrne
seznam podseznamov, ki določene dolžine,nastavi_dolzino
, ki določi dolžino podseznamov.
Privzeta dolžina, ki se uporablja, če ne pokličemo te metode, je
2
.Dodatne naloge ni.
Testi: testi.py
Rezalnik si bo moral zapomniti eno stvar: širino. Konstruktor jo
nastavi na 2
, nastavi_dolzino
jo spremeni.
razrezi(s)
gre prek vseh možnih začetkov koščkov, torej
for i in range(0, len(s), self.dolzina)
in za vsakega
sestavi košček, s[i:i + self.dolzina]
.
class Rezalnik:
def __init__(self):
self.dolzina = 2
def nastavi_dolzino(self, dolzina):
self.dolzina = dolzina
def razrezi(self, s):
return [s[i:i + self.dolzina]
for i in range(0, len(s), self.dolzina)]
= ["Ana", "Berta", "Cilka", "Donald", "Ema", "Fanči", "Greta", "Helga", "Iva"]
s
= Rezalnik() rezalnik
rezalnik.razrezi(s)
[['Ana', 'Berta'],
['Cilka', 'Donald'],
['Ema', 'Fanči'],
['Greta', 'Helga'],
['Iva']]
3) rezalnik.nastavi_dolzino(
rezalnik.razrezi(s)
[['Ana', 'Berta', 'Cilka'],
['Donald', 'Ema', 'Fanči'],
['Greta', 'Helga', 'Iva']]
Da reč naredimo malo naprednejšo, napišimo funkcijo
chunked(s, i)
, ki ji podamo nekaj, kar je potrebno
razrezati in dolžino, vrne pa, kar vrača gornji
razrezi
.
def chunked(s, dolzina):
return [s[i:i + dolzina]
for i in range(0, len(s), dolzina)]
Funkcija deluje tudi na nizih.
"Benjamin", 2) chunked(
['Be', 'nj', 'am', 'in']
Ne deluje pa na generatorjih.
Na hitro sestavimo generator praštevil do 100 in jih razsekajmo v trojke.
= (x for x in range(2, 100) if all(x % n != 0 for n in range(2, x)))
g
3) chunked(g,
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-8-f22d355f7e54> in <module>
1 g = (x for x in range(2, 100) if all(x % n != 0 for n in range(2, x)))
2
----> 3 chunked(g, 3)
<ipython-input-6-4ca9b12daeac> in chunked(s, dolzina)
1 def chunked(s, dolzina):
2 return [s[i:i + dolzina]
----> 3 for i in range(0, len(s), dolzina)]
TypeError: object of type 'generator' has no len()
To ne deluje, ker generatorji nimajo dolžine (nihče ne ve vnaprej, koliko stvari bodo zgenerirali), poleg tega pa jih ni mogoče indeksirati.
Šlo bi tako.
def chunked(s, dolzina):
= []
kosi for i, x in enumerate(s):
if i % dolzina == 0: # smo na meji, začenjamo nov kos
kosi.append([])-1].append(x) # dodamo v zadnji kos
kosi[return kosi
= (x for x in range(2, 100) if all(x % n != 0 for n in range(2, x)))
g
3) chunked(g,
[[2, 3, 5],
[7, 11, 13],
[17, 19, 23],
[29, 31, 37],
[41, 43, 47],
[53, 59, 61],
[67, 71, 73],
[79, 83, 89],
[97]]
Deluje, ni pa posebej zabavno. Sprogramirajmo tako, da bo.
def chunked(s, size):
= iter(s)
s while True:
= [x for _, x in zip(range(size), s)]
chunk if not chunk:
break
yield chunk
Najprej spremenimo s
v iterator. To storimo zato, da bo
kasneje, ko jo kličemo znotraj zip
, dajala vedno nove
elemente, ne pa začenjala vedno od začetka.
Glavni trik je zip(range(size), s)
. Ker se
zip
konča takrat, ko zmanjka elementov krajšega od
seznamov, bo iz s
pobral le size
elementov.
To, kar vrača range
, nas v resnici ne zanima, torej
x for _, x in ...
. Tako sestavimo trenutni kos. Če je
prazen, je veselja konec. Če ni, ga vrnemo - z yield
, ker
je dodatno imenitno, da je naš chunked
generator.
= (x for x in range(2, 100) if all(x % n != 0 for n in range(2, x)))
g
3) chunked(g,
<generator object chunked at 0x7fc747e4b4d0>
list(chunked(g, 3))
[[2, 3, 5],
[7, 11, 13],
[17, 19, 23],
[29, 31, 37],
[41, 43, 47],
[53, 59, 61],
[67, 71, 73],
[79, 83, 89],
[97]]
Razred je potem takšen.
class Rezalnik:
def __init__(self):
self.dolzina = 2
def nastavi_dolzino(self, dolzina):
self.dolzina = dolzina
def razrezi(self, s):
return list(chunked(s, self.dolzina))