У мене є список довільної довжини, і мені потрібно розбити його на однакові за розміром шматки і оперувати ними. Є кілька очевидних способів зробити це, наприклад, вести лічильник і два списки, і коли другий список заповнюється, додавати його до першого списку і очищати другий список для наступного циклу даних, але це потенційно надзвичайно дорого.
Мені цікаво, чи є у когось хороше рішення для списків будь-якої довжини, наприклад, з використанням генераторів.
Я шукав щось корисне в itertools
, але не зміг знайти нічого очевидно корисного. Хоча, можливо, я щось пропустив.
Пов'язане питання: Який найбільш "пітонічний" спосіб ітерації над списком по частинах?
Ось генератор, який видає шматки, які ви хочете:
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]]
Якщо ви використовуєте Python 2, вам слід використовувати xrange()
замість 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]
Також ви можете просто використовувати обробку списків замість написання функції, хоча краще інкапсулювати такі операції в іменовані функції, щоб ваш код було легше зрозуміти. Python 3:
[l[i:i + n] for i in range(0, len(l), n)]
Версія Python 2:
[l[i:i + n] for i in xrange(0, len(l), n)]
Наведемо генератор, який працює на довільних ітераціях:
def split_seq(iterable, size):
it = iter(iterable)
item = list(itertools.islice(it, size))
while item:
yield item
item = list(itertools.islice(it, size))
Приклад:
>>> 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]]
Якщо ви знаєте розмір списку:
def SplitList(mylist, chunk_size):
return [mylist[offs:offs+chunk_size] for offs in range(0, len(mylist), chunk_size)]
Якщо не знаєте (ітератор):
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
В останньому випадку це можна перефразувати більш красивим чином, якщо можна бути впевненим, що послідовність завжди містить цілу кількість відрізків заданого розміру (тобто немає неповного останнього відрізка).