Como você dividir uma lista em pedaços de tamanho uniforme?
Pergunta
Eu tenho uma lista de comprimento arbitrário, e eu preciso dividi-la em pedaços de tamanho igual e operar nele. Existem algumas maneiras óbvias de fazer isso, como manter um balcão e duas listas, e quando a segunda lista enche, adicioná-lo à primeira lista e esvaziar a segunda lista para a próxima rodada de dados, mas isso é potencialmente extremamente caro.
Eu queria saber se alguém tinha uma boa solução para este para listas de qualquer comprimento, por exemplo, usando geradores.
Eu estava procurando por algo útil em itertools
mas eu não consegui encontrar nada, obviamente útil. Poderia ter perdido, no entanto.
questão relacionada: Qual é a maneira mais “pythônico” para iterar sobre uma lista em pedaços?
Solução
Aqui está um gerador que produz os pedaços que você quer:
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]]
Se você estiver usando Python 2, você deve usar xrange()
vez de 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]
Além disso, você pode simplesmente usar compreensão de lista em vez de escrever uma função, mas é uma boa idéia para operações Encapsular como este em funções nomeadas para que seu código é mais fácil de entender. Python 3:
[l[i:i + n] for i in range(0, len(l), n)]
Python 2 versão:
[l[i:i + n] for i in xrange(0, len(l), n)]
Outras dicas
Se você quer algo super simples:
def chunks(l, n):
n = max(1, n)
return (l[i:i+n] for i in xrange(0, len(l), n))
Use range()
vez de xrange()
no caso de Python 3.x
directamente a partir da (antiga) documentação Python (receitas para itertools):
from itertools import izip, chain, repeat
def grouper(n, iterable, padvalue=None):
"grouper(3, 'abcdefg', 'x') --> ('a','b','c'), ('d','e','f'), ('g','x','x')"
return izip(*[chain(iterable, repeat(padvalue, n-1))]*n)
A versão atual, como sugerido por J.F.Sebastian:
#from itertools import izip_longest as zip_longest # for Python 2.x
from itertools import zip_longest # for Python 3.x
#from six.moves import zip_longest # for both (uses the six compat library)
def grouper(n, iterable, padvalue=None):
"grouper(3, 'abcdefg', 'x') --> ('a','b','c'), ('d','e','f'), ('g','x','x')"
return zip_longest(*[iter(iterable)]*n, fillvalue=padvalue)
Eu acho obras-trabalhou-se Time Machine da Guido trabalhar a terá trabalhado-se a trabalhar novamente.
Estas soluções funcionam porque [iter(iterable)]*n
(ou o equivalente na versão anterior) cria um iteradoras, tempos n
utilizadas na lista. izip_longest
então efetivamente executa um round-robin de "cada" iteração; porque este é o mesmo iterador, é avançado por cada tal chamada, resultando em cada um desses zip-roundrobin geradora de uma tupla de itens n
.
Eu sei que isto é uma espécie de velho, mas eu não sei porque ninguém mencionou numpy.array_split
:
lst = range(50)
In [26]: np.array_split(lst,5)
Out[26]:
[array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]),
array([10, 11, 12, 13, 14, 15, 16, 17, 18, 19]),
array([20, 21, 22, 23, 24, 25, 26, 27, 28, 29]),
array([30, 31, 32, 33, 34, 35, 36, 37, 38, 39]),
array([40, 41, 42, 43, 44, 45, 46, 47, 48, 49])]
Estou surpreso que ninguém tenha pensado em usar forma de dois argumento de iter
:
from itertools import islice
def chunk(it, size):
it = iter(it)
return iter(lambda: tuple(islice(it, size)), ())
Demonstração:
>>> list(chunk(range(14), 3))
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13)]
Isso funciona com qualquer iterable e produz uma saída preguiçosamente. Ele retorna tuplas em vez de iteradores, mas acho que ele tem uma certa elegância no entanto. Ele também não pad; se você quiser preenchimento, uma simples variação do bastam vontade acima:
from itertools import islice, chain, repeat
def chunk_pad(it, size, padval=None):
it = chain(iter(it), repeat(padval))
return iter(lambda: tuple(islice(it, size)), (padval,) * size)
Demonstração:
>>> list(chunk_pad(range(14), 3))
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13, None)]
>>> list(chunk_pad(range(14), 3, 'a'))
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13, 'a')]
Como as soluções baseadas izip_longest
, o acima sempre almofadas. Tanto quanto eu sei, não há nenhuma itertools receita de uma ou de duas linhas para uma função que opcionalmente almofadas. Ao combinar o acima duas abordagens, este vem muito perto:
_no_padding = object()
def chunk(it, size, padval=_no_padding):
if padval == _no_padding:
it = iter(it)
sentinel = ()
else:
it = chain(iter(it), repeat(padval))
sentinel = (padval,) * size
return iter(lambda: tuple(islice(it, size)), sentinel)
Demonstração:
>>> list(chunk(range(14), 3))
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13)]
>>> list(chunk(range(14), 3, None))
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13, None)]
>>> list(chunk(range(14), 3, 'a'))
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13, 'a')]
Eu acredito que este é o chunker menor propôs que ofertas preenchimento opcional.
Como Tomasz Gandor observado , os dois Chunkers preenchimento vai parar inesperadamente se eles encontram uma longa sequência de valores almofada. Aqui está uma variação final que funciona em torno esse problema em uma forma razoável:
_no_padding = object()
def chunk(it, size, padval=_no_padding):
it = iter(it)
chunker = iter(lambda: tuple(islice(it, size)), ())
if padval == _no_padding:
yield from chunker
else:
for ch in chunker:
yield ch if len(ch) == size else ch + (padval,) * (size - len(ch))
Demonstração:
>>> list(chunk([1, 2, (), (), 5], 2))
[(1, 2), ((), ()), (5,)]
>>> list(chunk([1, 2, None, None, 5], 2, None))
[(1, 2), (None, None), (5, None)]
Aqui é um gerador que os trabalhos sobre iterables arbitrárias:
def split_seq(iterable, size):
it = iter(iterable)
item = list(itertools.islice(it, size))
while item:
yield item
item = list(itertools.islice(it, size))
Exemplo:
>>> 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 chunk(input, size):
return map(None, *([iter(input)] * size))
Simples e elegante
l = range(1, 1000)
print [l[x:x+10] for x in xrange(0, len(l), 10)]
ou, se preferir:
chunks = lambda l, n: [l[x: x+n] for x in xrange(0, len(l), n)]
chunks(l, 10)
Eu vi a resposta Python-ish mais impressionante em um duplicado desta pergunta:
from itertools import zip_longest
a = range(1, 16)
i = iter(a)
r = list(zip_longest(i, i, i))
>>> print(r)
[(1, 2, 3), (4, 5, 6), (7, 8, 9), (10, 11, 12), (13, 14, 15)]
Você pode criar n-tuple para qualquer n. Se a = range(1, 15)
, em seguida, o resultado será:
[(1, 2, 3), (4, 5, 6), (7, 8, 9), (10, 11, 12), (13, 14, None)]
Se a lista está dividida uniformemente, então você pode substituir zip_longest
com zip
, caso contrário o (13, 14, None)
trio estaria perdido. Python 3 é usado acima. Para Python 2, uso izip_longest
.
Crítica de outras respostas aqui:
Nenhuma dessas respostas são uniformemente pedaços de tamanho, todos eles deixam um pedaço nanico no final, então eles não estão completamente equilibrados. Se você estivesse usando essas funções para distribuir o trabalho, que você construiu-in a perspectiva de um acabamento provavelmente bem antes dos outros, para que ele iria ficar sentado sem fazer nada, enquanto os outros continuaram trabalhando duro.
Por exemplo, as extremidades resposta top atuais com:
[60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
[70, 71, 72, 73, 74]]
Eu odeio que nanico no final!
Outros, como list(grouper(3, xrange(7)))
e chunk(xrange(7), 3)
tanto retorno: [(0, 1, 2), (3, 4, 5), (6, None, None)]
. Do None
estão apenas acolchoar, e bastante deselegante na minha opinião. Eles não são uniformemente chunking os iterables.
Por que não podemos dividi-las melhor?
My Solution (s)
Aqui está uma solução equilibrada, adaptada de uma função que eu usei na produção (Nota em Python 3 para substituir xrange
com range
):
def baskets_from(items, maxbaskets=25):
baskets = [[] for _ in xrange(maxbaskets)] # in Python 3 use range
for i, item in enumerate(items):
baskets[i % maxbaskets].append(item)
return filter(None, baskets)
E eu criei um gerador que faz o mesmo, se você colocá-lo em uma lista:
def iter_baskets_from(items, maxbaskets=3):
'''generates evenly balanced baskets from indexable iterable'''
item_count = len(items)
baskets = min(item_count, maxbaskets)
for x_i in xrange(baskets):
yield [items[y_i] for y_i in xrange(x_i, item_count, baskets)]
E, finalmente, desde que eu ver que todas as funções acima elementos retornam em uma ordem contígua (como eles foram dadas):
def iter_baskets_contiguous(items, maxbaskets=3, item_count=None):
'''
generates balanced baskets from iterable, contiguous contents
provide item_count if providing a iterator that doesn't support len()
'''
item_count = item_count or len(items)
baskets = min(item_count, maxbaskets)
items = iter(items)
floor = item_count // baskets
ceiling = floor + 1
stepdown = item_count % baskets
for x_i in xrange(baskets):
length = ceiling if x_i < stepdown else floor
yield [items.next() for _ in xrange(length)]
saída
Para testá-los:
print(baskets_from(xrange(6), 8))
print(list(iter_baskets_from(xrange(6), 8)))
print(list(iter_baskets_contiguous(xrange(6), 8)))
print(baskets_from(xrange(22), 8))
print(list(iter_baskets_from(xrange(22), 8)))
print(list(iter_baskets_contiguous(xrange(22), 8)))
print(baskets_from('ABCDEFG', 3))
print(list(iter_baskets_from('ABCDEFG', 3)))
print(list(iter_baskets_contiguous('ABCDEFG', 3)))
print(baskets_from(xrange(26), 5))
print(list(iter_baskets_from(xrange(26), 5)))
print(list(iter_baskets_contiguous(xrange(26), 5)))
que imprime:
[[0], [1], [2], [3], [4], [5]]
[[0], [1], [2], [3], [4], [5]]
[[0], [1], [2], [3], [4], [5]]
[[0, 8, 16], [1, 9, 17], [2, 10, 18], [3, 11, 19], [4, 12, 20], [5, 13, 21], [6, 14], [7, 15]]
[[0, 8, 16], [1, 9, 17], [2, 10, 18], [3, 11, 19], [4, 12, 20], [5, 13, 21], [6, 14], [7, 15]]
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11], [12, 13, 14], [15, 16, 17], [18, 19], [20, 21]]
[['A', 'D', 'G'], ['B', 'E'], ['C', 'F']]
[['A', 'D', 'G'], ['B', 'E'], ['C', 'F']]
[['A', 'B', 'C'], ['D', 'E'], ['F', 'G']]
[[0, 5, 10, 15, 20, 25], [1, 6, 11, 16, 21], [2, 7, 12, 17, 22], [3, 8, 13, 18, 23], [4, 9, 14, 19, 24]]
[[0, 5, 10, 15, 20, 25], [1, 6, 11, 16, 21], [2, 7, 12, 17, 22], [3, 8, 13, 18, 23], [4, 9, 14, 19, 24]]
[[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]]
Observe que o gerador contígua fornecer pedaços nos mesmos padrões comprimento que os outros dois, mas os itens são todos em ordem, e eles são tão uniformemente dividida como se pode dividir uma lista de elementos discretos.
Se você sabe o tamanho da lista:
def SplitList(mylist, chunk_size):
return [mylist[offs:offs+chunk_size] for offs in range(0, len(mylist), chunk_size)]
Se você não fizer isso (um iterador):
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
Neste último caso, pode ser reformulada de forma mais bonita se você pode ter certeza de que a sequência contém sempre um número inteiro de pedaços de determinado tamanho (ou seja, não há nenhuma incompleta último bloco).
Se você tinha um tamanho pedaço de 3 por exemplo, você poderia fazer:
zip(*[iterable[i::3] for i in range(3)])
Fonte: http://code.activestate.com/recipes/303060-group -a-lista-em-sequencial-n-tuplos /
Gostaria de usar este número quando o meu tamanho do bloco é fixo posso digitar, por exemplo, '3', e nunca iria mudar.
O Toolz biblioteca tem a função partition
para isso:
from toolz.itertoolz.core import partition
list(partition(2, [1, 2, 3, 4]))
[(1, 2), (3, 4)]
Eu gosto da versão do doc Python proposto por tzot e J.F.Sebastian muito, mas tem dois problemas:
- não é muito explícita ??li>
- Eu normalmente não quer um valor de preenchimento no último pedaço
Eu estou usando esta muito no meu código:
from itertools import islice
def chunks(n, iterable):
iterable = iter(iterable)
while True:
yield tuple(islice(iterable, n)) or iterable.next()
UPDATE: Uma versão pedaços preguiçoso:
from itertools import chain, islice
def chunks(n, iterable):
iterable = iter(iterable)
while True:
yield chain([next(iterable)], islice(iterable, n-1))
Neste ponto, acho que precisamos de um recursiva gerador , apenas no caso ...
Em python 2:
def chunks(li, n):
if li == []:
return
yield li[:n]
for e in chunks(li[n:], n):
yield e
Em Python 3:
def chunks(li, n):
if li == []:
return
yield li[:n]
yield from chunks(li[n:], n)
Além disso, em caso de enorme invasão alienígena, a Decorado recursiva gerador pode tornar-se útil:
def dec(gen):
def new_gen(li, n):
for e in gen(li, n):
if e == []:
return
yield e
return new_gen
@dec
def chunks(li, n):
yield li[:n]
for e in chunks(li[n:], n):
yield e
Você também pode usar get_chunks
função de utilspie
biblioteca como:
>>> from utilspie import iterutils
>>> a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> list(iterutils.get_chunks(a, 5))
[[1, 2, 3, 4, 5], [6, 7, 8, 9]]
Você pode instalar utilspie
via pip:
sudo pip install utilspie
Disclaimer:. Eu sou o criador do utilspie biblioteca
Eu estava curioso sobre o desempenho de diferentes abordagens e aqui está:
Testado em Python 3.5.1
import time
batch_size = 7
arr_len = 298937
#---------slice-------------
print("\r\nslice")
start = time.time()
arr = [i for i in range(0, arr_len)]
while True:
if not arr:
break
tmp = arr[0:batch_size]
arr = arr[batch_size:-1]
print(time.time() - start)
#-----------index-----------
print("\r\nindex")
arr = [i for i in range(0, arr_len)]
start = time.time()
for i in range(0, round(len(arr) / batch_size + 1)):
tmp = arr[batch_size * i : batch_size * (i + 1)]
print(time.time() - start)
#----------batches 1------------
def batch(iterable, n=1):
l = len(iterable)
for ndx in range(0, l, n):
yield iterable[ndx:min(ndx + n, l)]
print("\r\nbatches 1")
arr = [i for i in range(0, arr_len)]
start = time.time()
for x in batch(arr, batch_size):
tmp = x
print(time.time() - start)
#----------batches 2------------
from itertools import islice, chain
def batch(iterable, size):
sourceiter = iter(iterable)
while True:
batchiter = islice(sourceiter, size)
yield chain([next(batchiter)], batchiter)
print("\r\nbatches 2")
arr = [i for i in range(0, arr_len)]
start = time.time()
for x in batch(arr, batch_size):
tmp = x
print(time.time() - start)
#---------chunks-------------
def chunks(l, n):
"""Yield successive n-sized chunks from l."""
for i in range(0, len(l), n):
yield l[i:i + n]
print("\r\nchunks")
arr = [i for i in range(0, arr_len)]
start = time.time()
for x in chunks(arr, batch_size):
tmp = x
print(time.time() - start)
#-----------grouper-----------
from itertools import zip_longest # for Python 3.x
#from six.moves import zip_longest # for both (uses the six compat library)
def grouper(iterable, n, padvalue=None):
"grouper(3, 'abcdefg', 'x') --> ('a','b','c'), ('d','e','f'), ('g','x','x')"
return zip_longest(*[iter(iterable)]*n, fillvalue=padvalue)
arr = [i for i in range(0, arr_len)]
print("\r\ngrouper")
start = time.time()
for x in grouper(arr, batch_size):
tmp = x
print(time.time() - start)
Resultados:
slice
31.18285083770752
index
0.02184295654296875
batches 1
0.03503894805908203
batches 2
0.22681021690368652
chunks
0.019841909408569336
grouper
0.006506919860839844
[AA[i:i+SS] for i in range(len(AA))[::SS]]
Onde AA é array, SS é do tamanho do fragmento. Por exemplo:
>>> AA=range(10,21);SS=3
>>> [AA[i:i+SS] for i in range(len(AA))[::SS]]
[[10, 11, 12], [13, 14, 15], [16, 17, 18], [19, 20]]
# or [range(10, 13), range(13, 16), range(16, 19), range(19, 21)] in py3
código:
def split_list(the_list, chunk_size):
result_list = []
while the_list:
result_list.append(the_list[:chunk_size])
the_list = the_list[chunk_size:]
return result_list
a_list = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print split_list(a_list, 3)
resultado:
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
heh, uma versão de linha
In [48]: chunk = lambda ulist, step: map(lambda i: ulist[i:i+step], xrange(0, len(ulist), step))
In [49]: chunk(range(1,100), 10)
Out[49]:
[[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, 75, 76, 77, 78, 79, 80],
[81, 82, 83, 84, 85, 86, 87, 88, 89, 90],
[91, 92, 93, 94, 95, 96, 97, 98, 99]]
def split_seq(seq, num_pieces):
start = 0
for i in xrange(num_pieces):
stop = start + len(seq[i::num_pieces])
yield seq[start:stop]
start = stop
uso:
seq = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
for seq in split_seq(seq, 3):
print seq
Outra versão mais explícito.
def chunkList(initialList, chunkSize):
"""
This function chunks a list into sub lists
that have a length equals to chunkSize.
Example:
lst = [3, 4, 9, 7, 1, 1, 2, 3]
print(chunkList(lst, 3))
returns
[[3, 4, 9], [7, 1, 1], [2, 3]]
"""
finalList = []
for i in range(0, len(initialList), chunkSize):
finalList.append(initialList[i:i+chunkSize])
return finalList
Sem pôr len () que é bom para grandes listas:
def splitter(l, n):
i = 0
chunk = l[:n]
while chunk:
yield chunk
i += n
chunk = l[i:i+n]
E isto é para iterables:
def isplitter(l, n):
l = iter(l)
chunk = list(islice(l, n))
while chunk:
yield chunk
chunk = list(islice(l, n))
O sabor funcional do acima:
def isplitter2(l, n):
return takewhile(bool,
(tuple(islice(start, n))
for start in repeat(iter(l))))
OR:
def chunks_gen_sentinel(n, seq):
continuous_slices = imap(islice, repeat(iter(seq)), repeat(0), repeat(n))
return iter(imap(tuple, continuous_slices).next,())
OR:
def chunks_gen_filter(n, seq):
continuous_slices = imap(islice, repeat(iter(seq)), repeat(0), repeat(n))
return takewhile(bool,imap(tuple, continuous_slices))
Mais uma solução
def make_chunks(data, chunk_size):
while data:
chunk, data = data[:chunk_size], data[chunk_size:]
yield chunk
>>> for chunk in make_chunks([1, 2, 3, 4, 5, 6, 7], 2):
... print chunk
...
[1, 2]
[3, 4]
[5, 6]
[7]
>>>
Considere o uso matplotlib.cbook peças
Por exemplo:
import matplotlib.cbook as cbook
segments = cbook.pieces(np.arange(20), 3)
for s in segments:
print s
>>> orange = range(1, 1001)
>>> otuples = list( zip(*[iter(orange)]*10))
>>> print(otuples)
[(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), ... (991, 992, 993, 994, 995, 996, 997, 998, 999, 1000)]
>>> olist = [list(i) for i in otuples]
>>> print(olist)
[[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], ..., [991, 992, 993, 994, 995, 996, 997, 998, 999, 1000]]
>>>
Python3
a = [1, 2, 3, 4, 5, 6, 7, 8, 9]
CHUNK = 4
[a[i*CHUNK:(i+1)*CHUNK] for i in xrange((len(a) + CHUNK - 1) / CHUNK )]
Neste ponto, eu acho que nós precisamos a função anônima recursiva obrigatório.
Y = lambda f: (lambda x: x(x))(lambda y: f(lambda *args: y(y)(*args)))
chunks = Y(lambda f: lambda n: [n[0][:n[1]]] + f((n[0][n[1]:], n[1])) if len(n[0]) > 0 else [])
Uma vez que todos aqui falando sobre iteradores. boltons
tem método perfeito para isso, chamado de iterutils.chunked_iter
.
from boltons import iterutils
list(iterutils.chunked_iter(list(range(50)), 11))
Output:
[[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]]
Mas se você não quer ser misericórdia de memória, você pode usar old-way e armazenar o list
completa em primeiro lugar com iterutils.chunked
.
Aqui está uma lista de abordagens adicionais:
Dada
import itertools as it
import collections as ct
import more_itertools as mit
iterable = range(11)
n = 3
Código
A Biblioteca Padrão
list(it.zip_longest(*[iter(iterable)] * n))
# [(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, None)]
d = {}
for i, x in enumerate(iterable):
d.setdefault(i//n, []).append(x)
list(d.values())
# [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10]]
dd = ct.defaultdict(list)
for i, x in enumerate(iterable):
dd[i//n].append(x)
list(dd.values())
# [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10]]
list(mit.chunked(iterable, n))
# [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10]]
list(mit.sliced(iterable, n))
# [range(0, 3), range(3, 6), range(6, 9), range(9, 11)]
list(mit.grouper(n, iterable))
# [(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, None)]
list(mit.windowed(iterable, len(iterable)//n, step=n))
# [(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, None)]
Referências
-
zip_longest
(related pós , related pós ) -
setdefault
(resultados ordenados requer Python 3.6 +) -
collections.defaultdict
(resultados ordenados requer Python 3.6 +) -
more_itertools.chunked
( relacionados postou ) -
more_itertools.sliced
-
more_itertools.grouper
( relacionado com o pós ) -
more_itertools.windowed
(ver tambémstagger
,zip_offset
)
+ Uma biblioteca de terceiros que implementa itertools receitas e muito mais. > pip install more_itertools