Turiu bet kokio ilgio sąrašą, kurį reikia suskaidyti į vienodo dydžio dalis ir su juo atlikti operaciją. Yra keletas akivaizdžių būdų, kaip tai padaryti, pavyzdžiui, laikyti skaitiklį ir du sąrašus, o antrajam sąrašui užsipildžius, pridėti jį prie pirmojo sąrašo ir ištuštinti antrąjį sąrašą kitam duomenų ciklui, tačiau tai gali būti labai brangu.
Norėjau sužinoti, ar kas nors turi gerą sprendimą, kaip tai padaryti su bet kokio ilgio sąrašais, pvz., naudojant generatorius.
Ieškojau ko nors naudingo itertools
, bet nieko akivaizdžiai naudingo neradau. Tačiau galėjau tai praleisti.
Susijęs klausimas: Koks yra "pitoniškiausias" būdas iteruoti sąrašą dalimis?
Čia pateikiamas generatorius, kuris sukuria norimus gabalėlius:
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]]
Jei naudojate Python 2, turėtumėte naudoti xrange()
, o ne range()
:
def chunks(l, n):
"""Yield successive n-sized chunks from l."""
for i in xrange(0, len(l), n):
yield l[i:i + n]
Be to, užuot rašę funkciją, galite paprasčiausiai naudoti sąrašo supratimą, tačiau tokias operacijas verta įvardyti į pavadintas funkcijas, kad kodą būtų lengviau suprasti. Python 3:
[l[i:i + n] for i in range(0, len(l), n)]
Python 2 versija:
[l[i:i + n] for i in xrange(0, len(l), n)]
Čia pateikiamas generatorius, kuris veikia su bet kokiomis iterablėmis:
def split_seq(iterable, size):
it = iter(iterable)
item = list(itertools.islice(it, size))
while item:
yield item
item = list(itertools.islice(it, size))
Pavyzdys:
>>> 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]]
Jei žinote sąrašo dydį:
def SplitList(mylist, chunk_size):
return [mylist[offs:offs+chunk_size] for offs in range(0, len(mylist), chunk_size)]
Jei nežinote (iteratorius):
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
Pastaruoju atveju jį galima perfrazuoti gražiau, jei galite būti tikri, kad sekoje visada yra visas skaičius duoto dydžio gabalėlių (t. y. nėra neužbaigto paskutinio gabalėlio).