Ik heb een lijst van willekeurige lengte, en ik moet die opsplitsen in even grote brokken en die bewerken. Er zijn enkele voor de hand liggende manieren om dit te doen, zoals een teller en twee lijsten bijhouden, en als de tweede lijst vol is, deze toevoegen aan de eerste lijst en de tweede lijst leegmaken voor de volgende dataronde, maar dit is potentieel extreem duur.
Ik vroeg me af of iemand hier een goede oplossing voor heeft voor lijsten van elke lengte, bijvoorbeeld met behulp van generatoren.
Ik zocht naar iets bruikbaars in itertools
, maar ik kon niets duidelijk bruikbaars vinden. Misschien heb ik het gemist, hoewel.
Verwante vraag: Wat is de meest "pythonische" manier om over een lijst in chunks te itereren?
Hier's een generator die de brokken oplevert die je wilt:
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]]
Als je Python 2 gebruikt, moet je xrange()
gebruiken in plaats van 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]
Je kunt ook gewoon list comprehension gebruiken in plaats van een functie te schrijven, hoewel het'een goed idee is om operaties als deze in te kapselen in named functions, zodat je code makkelijker te begrijpen is. Python 3:
[l[i:i + n] for i in range(0, len(l), n)]
Python 2 versie:
[l[i:i + n] for i in xrange(0, len(l), n)]
Hier is een generator die werkt op willekeurige iterabelen:
def split_seq(iterable, size):
it = iter(iterable)
item = list(itertools.islice(it, size))
while item:
yield item
item = list(itertools.islice(it, size))
Voorbeeld:
>>> 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]]
Als je de grootte van de lijst weet:
def SplitList(mylist, chunk_size):
return [mylist[offs:offs+chunk_size] for offs in range(0, len(mylist), chunk_size)]
Als je dat niet weet (een 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
In het laatste geval kan het mooier geherformuleerd worden als je er zeker van kunt zijn dat de sequentie altijd een geheel aantal chunks van gegeven grootte bevat (er is dus geen onvolledige laatste chunk).