Imam poljubno dolg seznam, ki ga moram razdeliti na enako velike dele in ga obdelati. Obstaja nekaj očitnih načinov za to, kot je vodenje števca in dveh seznamov, in ko se drugi seznam napolni, ga dodamo na prvi seznam in izpraznimo drugi seznam za naslednji krog podatkov, vendar je to potencialno zelo drago.
Zanimalo me je, ali ima kdo dobro rešitev za to za sezname poljubne dolžine, npr. z uporabo generatorjev.
Iskal sem kaj uporabnega v itertools
, vendar nisem našel ničesar očitno uporabnega. Morda pa sem kaj spregledal.
Sorodno vprašanje: Kakšen je najbolj "pitonski" način za iteracijo po seznamu v kosih?
Tukaj je generator, ki omogoča pridobivanje želenih kosov:
def chunks(l, n):
"""Yield successive n-sized chunks from l."""
for i in range(0, len(l), n):
yield l[i:i + n]
import pprint
pprint.pprint(list(chunks(range(10, 75), 10)))
[[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
[20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
[30, 31, 32, 33, 34, 35, 36, 37, 38, 39],
[40, 41, 42, 43, 44, 45, 46, 47, 48, 49],
[50, 51, 52, 53, 54, 55, 56, 57, 58, 59],
[60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
[70, 71, 72, 73, 74]]
Če uporabljate Python 2, morate namesto range()
uporabiti xrange()
:
def chunks(l, n):
"""Yield successive n-sized chunks from l."""
for i in xrange(0, len(l), n):
yield l[i:i + n]
Prav tako lahko namesto pisanja funkcije preprosto uporabite razumevanje seznama, čeprav je dobro, da takšne operacije zapakirate v poimenovane funkcije, da bo vaša koda lažje razumljiva. Python 3:
[l[i:i + n] for i in range(0, len(l), n)]
Različica Python 2:
[l[i:i + n] for i in xrange(0, len(l), n)]
Tukaj je generator, ki deluje na poljubnih iterablah:
def split_seq(iterable, size):
it = iter(iterable)
item = list(itertools.islice(it, size))
while item:
yield item
item = list(itertools.islice(it, size))
Primer:
>>> import pprint
>>> pprint.pprint(list(split_seq(xrange(75), 10)))
[[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
[10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
[20, 21, 22, 23, 24, 25, 26, 27, 28, 29],
[30, 31, 32, 33, 34, 35, 36, 37, 38, 39],
[40, 41, 42, 43, 44, 45, 46, 47, 48, 49],
[50, 51, 52, 53, 54, 55, 56, 57, 58, 59],
[60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
[70, 71, 72, 73, 74]]
Če poznate velikost seznama:
def SplitList(mylist, chunk_size):
return [mylist[offs:offs+chunk_size] for offs in range(0, len(mylist), chunk_size)]
Če ne (iterator):
def IterChunks(sequence, chunk_size):
res = []
for item in sequence:
res.append(item)
if len(res) >= chunk_size:
yield res
res = []
if res:
yield res # yield the last, incomplete, portion
V slednjem primeru se lahko preoblikuje na lepši način, če ste lahko prepričani, da zaporedje vedno vsebuje celo število kosov dane velikosti (tj. ni nepopolnega zadnjega kosa).