web-dev-qa-db-fra.com

Comment diviser une liste en morceaux de taille égale?

J'ai une liste de longueur arbitraire, et je dois la diviser en morceaux de taille égale et l'exploiter. Il existe des moyens évidents de le faire, comme garder un compteur et deux listes, et lorsque la deuxième liste est pleine, ajoutez-le à la première liste et videz la deuxième liste pour le prochain cycle de données, mais cela peut être extrêmement coûteux.

Je me demandais si quelqu'un avait une bonne solution à cela pour des listes de toute longueur, par exemple. en utilisant des générateurs.

Je cherchais quelque chose d’utile dans itertools mais je n’ai rien trouvé qui soit manifestement utile. J'aurais peut-être manqué ça.

Question connexe: Quel est le moyen le plus “pythonique” d’itérer une liste en morceaux?

1985
jespern

Voici un générateur qui donne les morceaux que vous voulez:

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]]

Si vous utilisez Python 2, vous devez utiliser xrange() au lieu 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]

Vous pouvez également utiliser simplement la compréhension de liste au lieu d’écrire une fonction, bien que c’est une bonne idée d’encapsuler de telles opérations dans des fonctions nommées pour que votre code soit plus facile à comprendre. Python 3:

[l[i:i + n] for i in range(0, len(l), n)]

Version Python 2:

[l[i:i + n] for i in xrange(0, len(l), n)]
2709
Ned Batchelder

Si vous voulez quelque chose de super simple:

def chunks(l, n):
    n = max(1, n)
    return (l[i:i+n] for i in xrange(0, len(l), n))

Utilisez range() au lieu de xrange() dans le cas de Python 3.x

521
oremj

Directement à partir de la (ancienne) Python documentation (recettes pour 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)

La version actuelle, suggérée par 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)

Je suppose que la machine temporelle de Guido fonctionne - a fonctionné - fonctionnera - aura travaillé - fonctionnait à nouveau.

Ces solutions fonctionnent parce que [iter(iterable)]*n (ou l’équivalent dans la version précédente) crée n itérateur, répété n fois dans la liste. izip_longest effectue alors un va-et-vient de "chaque" itérateur; comme il s'agit du même itérateur, il est avancé par chacun de ces appels, de sorte que chaque Zip-roundrobin génère un tuple d'éléments n.

268
tzot

Je sais que c'est un peu vieux, mais je ne comprends pas pourquoi personne n'a mentionné 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])]
158
Moj

Je suis surpris que personne n'ait pensé à utiliser iter ' sous la forme de deux arguments :

from itertools import islice

def chunk(it, size):
    it = iter(it)
    return iter(lambda: Tuple(islice(it, size)), ())

Démo:

>>> list(chunk(range(14), 3))
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11), (12, 13)]

Cela fonctionne avec n’importe quelle valeur et produit une sortie paresseuse. Il retourne des tuples plutôt que des itérateurs, mais je pense qu'il a néanmoins une certaine élégance. De plus, il ne couvre pas; si vous voulez un rembourrage, une simple variation de ce qui précède suffira:

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)

Démo:

>>> 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')]

Comme les solutions basées sur izip_longest-, les pads précédents toujours . Autant que je sache, il n'y a pas de recette d'itertools à une ou deux lignes pour une fonction qui optionnellement remplit. En combinant les deux approches ci-dessus, celle-ci est assez proche:

_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)

Démo:

>>> 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')]

Je crois que c’est le chunker le plus court proposé qui offre un rembourrage optionnel.

Comme Tomasz Gandor observé , les deux chunkers s’arrêteront inopinément s’ils rencontrent une longue séquence de valeurs de pad. Voici une dernière variante qui résout ce problème de manière raisonnable:

_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))

Démo:

>>> list(chunk([1, 2, (), (), 5], 2))
[(1, 2), ((), ()), (5,)]
>>> list(chunk([1, 2, None, None, 5], 2, None))
[(1, 2), (None, None), (5, None)]
109
senderle

Voici un générateur qui travaille sur des itérables arbitraires:

def split_seq(iterable, size):
    it = iter(iterable)
    item = list(itertools.islice(it, size))
    while item:
        yield item
        item = list(itertools.islice(it, size))

Exemple:

>>> 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]]
87
Markus Jarderot
def chunk(input, size):
    return map(None, *([iter(input)] * size))
49
Tomasz Wysocki

Simple mais élégant

l = range(1, 1000)
print [l[x:x+10] for x in xrange(0, len(l), 10)]

ou si vous préférez:

chunks = lambda l, n: [l[x: x+n] for x in xrange(0, len(l), n)]
chunks(l, 10)
43
lebenf

J'ai vu la réponse Python-ish la plus impressionnante dans un duplicate de cette question:

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)]

Vous pouvez créer n-Tuple pour n’importe quel n. Si a = range(1, 15), le résultat sera:

[(1, 2, 3), (4, 5, 6), (7, 8, 9), (10, 11, 12), (13, 14, None)]

Si la liste est divisée en parts égales, vous pouvez remplacer Zip_longest par Zip, sinon le triplet (13, 14, None) serait perdu. Python 3 est utilisé ci-dessus. Pour Python 2, utilisez izip_longest.

35
Noich

Critique d'autres réponses ici:

Aucune de ces réponses ne sont des morceaux de taille égale, ils laissent tous un morceau à la fin, donc ils ne sont pas complètement équilibrés. Si vous utilisiez ces fonctions pour distribuer du travail, vous avez intégré la perspective que l’une finisse probablement bien avant les autres;.

Par exemple, la réponse actuelle se termine par:

[60, 61, 62, 63, 64, 65, 66, 67, 68, 69],
[70, 71, 72, 73, 74]]

Je déteste juste cette racaille à la fin!

D'autres, comme list(grouper(3, xrange(7))) et chunk(xrange(7), 3) renvoient tous deux: [(0, 1, 2), (3, 4, 5), (6, None, None)]. Les None ne sont que du rembourrage et sont plutôt inélégants à mon avis. Ils ne sont pas en train de diviser les iterables.

Pourquoi ne pouvons-nous pas mieux les partager?

Ma ou mes solutions

Voici une solution équilibrée, adaptée d’une fonction que j’avais utilisée en production (Remarque dans Python 3 pour remplacer xrange par 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) 

Et j'ai créé un générateur qui fait la même chose si vous le mettez dans une liste:

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)]

Et enfin, puisque je vois que toutes les fonctions ci-dessus renvoient des éléments dans un ordre contigu (comme ils ont été donnés):

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)]

Sortie

Pour les tester:

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)))

Qui 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]]

Notez que le générateur contigu fournit des morceaux de la même longueur que les deux autres, mais les éléments sont tous dans l’ordre, et ils sont divisés de la même manière qu’on peut diviser une liste d’éléments discrets.

33
Aaron Hall

Si vous connaissez la taille de la liste:

def SplitList(mylist, chunk_size):
    return [mylist[offs:offs+chunk_size] for offs in range(0, len(mylist), chunk_size)]

Si vous ne le faites pas (un itérateur):

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

Dans ce dernier cas, elle peut être reformulée de manière plus belle si vous pouvez être sûr que la séquence contient toujours un nombre entier de morceaux de taille donnée (c'est-à-dire qu'il n'y a pas de dernier morceau incomplet).

25
atzz

La bibliothèque toolz a la fonction partition pour cela:

from toolz.itertoolz.core import partition

list(partition(2, [1, 2, 3, 4]))
[(1, 2), (3, 4)]
16
zach

Si vous aviez une taille de morceau de 3 par exemple, vous pourriez faire:

Zip(*[iterable[i::3] for i in range(3)]) 

source: http://code.activestate.com/recipes/303060-group-a-list-into-sequential-n-tuples/

J'utiliserais cela lorsque ma taille de bloc est un nombre fixe que je peux taper, par exemple. '3' et ne changera jamais.

16
ninjagecko

Une expression génératrice:

def chunks(seq, n):
    return (seq[i:i+n] for i in xrange(0, len(seq), n))

par exemple.

print list(chunks(range(1, 1000), 10))
16
jamylak

J'aime bien la version de Python doc proposée par tzot et J.F.Sebastian, mais elle présente deux inconvénients:

  • ce n'est pas très explicite
  • Je ne veux généralement pas de valeur de remplissage dans le dernier morceau

J'utilise beaucoup celui-ci dans mon code:

from itertools import islice

def chunks(n, iterable):
    iterable = iter(iterable)
    while True:
        yield Tuple(islice(iterable, n)) or iterable.next()

MISE À JOUR: Une version de morceaux paresseux:

from itertools import chain, islice

def chunks(n, iterable):
   iterable = iter(iterable)
   while True:
       yield chain([next(iterable)], islice(iterable, n-1))
14
nikipore

À ce stade, je pense qu'il nous faut un générateur récursif, juste au cas où ...

Dans python 2:

def chunks(li, n):
    if li == []:
        return
    yield li[:n]
    for e in chunks(li[n:], n):
        yield e

Dans python 3:

def chunks(li, n):
    if li == []:
        return
    yield li[:n]
    yield from chunks(li[n:], n)

De plus, en cas d'invasion massive par des extraterrestres, un générateur récursif décoré pourrait devenir pratique:

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
12
mazieres

J'étais curieux de la performance de différentes approches et la voici:

Testé sur 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)

Résultats:

slice
31.18285083770752

index
0.02184295654296875

batches 1
0.03503894805908203

batches 2
0.22681021690368652

chunks
0.019841909408569336

grouper
0.006506919860839844
11
Alex T

Vous pouvez également utiliser la fonction get_chunks de utilspie en tant que:

_>>> 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]]
_

Vous pouvez installer utilspie via pip:

_Sudo pip install utilspie
_

Disclaimer: Je suis le créateur de la bibliothèque tilspie.

11
Moinuddin Quadri

code:

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)

résultat:

[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
11
Art B
[AA[i:i+SS] for i in range(len(AA))[::SS]]

Où AA est un tableau, SS est la taille du bloc. Par exemple:

>>> 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
10
Riaz Rizvi

Une autre version plus explicite.

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
7
Ranaivo
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

usage:

seq = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

for seq in split_seq(seq, 3):
    print seq
7
Corey Goldberg

heh, une version en ligne

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]]
7
slav0nic

Sans appeler len (), ce qui convient aux grandes listes:

def splitter(l, n):
    i = 0
    chunk = l[:n]
    while chunk:
        yield chunk
        i += n
        chunk = l[i:i+n]

Et ceci est pour iterables:

def isplitter(l, n):
    l = iter(l)
    chunk = list(islice(l, n))
    while chunk:
        yield chunk
        chunk = list(islice(l, n))

La saveur fonctionnelle de ce qui précède:

def isplitter2(l, n):
    return takewhile(bool,
                     (Tuple(islice(start, n))
                            for start in repeat(iter(l))))

OU:

def chunks_gen_sentinel(n, seq):
    continuous_slices = imap(islice, repeat(iter(seq)), repeat(0), repeat(n))
    return iter(imap(Tuple, continuous_slices).next,())

OU:

def chunks_gen_filter(n, seq):
    continuous_slices = imap(islice, repeat(iter(seq)), repeat(0), repeat(n))
    return takewhile(bool,imap(Tuple, continuous_slices))
7
Mars

Une autre solution

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]
>>> 

Voici une liste d'approches supplémentaires:

Étant donné

_import itertools as it
import collections as ct

import more_itertools as mit


iterable = range(11)
n = 3
_

Code

La bibliothèque standard

_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]]
_

more_itertools+

_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)]
_

Références

+ Une bibliothèque tierce qui implémente recettes d'itertools et plus. _> pip install more_itertools_

5
pylang

Puisque tout le monde ici parle d'itérateurs. boltons a une méthode parfaite pour cela, appelée iterutils.chunked_iter .

_from boltons import iterutils

list(iterutils.chunked_iter(list(range(50)), 11))
_

Sortie:

_[[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]]
_

Mais si vous ne voulez pas faire miséricorde à la mémoire, vous pouvez utiliser old-way et stocker le nom complet list à la première place avec iterutils.chunked .

5
vishes_shell

Voir cette référence

>>> 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

5
macm

À ce stade, je pense que nous avons besoin de la fonction obligatoire anonyme-récursif.

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 [])
5
Julien Palard

Pensez à utiliser matplotlib.cbook pièces

par exemple:

import matplotlib.cbook as cbook
segments = cbook.pieces(np.arange(20), 3)
for s in segments:
     print s
5
schwater
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 )]
5
AdvilUser

Vous pouvez utiliser la fonction array_split de numpy, par exemple np.array_split(np.array(data), 20), pour la scinder en 20 morceaux de taille presque égale.

Pour vous assurer que les morceaux ont exactement la même taille, utilisez np.split.

4
AlexG
def chunks(iterable,n):
    """assumes n is an integer>0
    """
    iterable=iter(iterable)
    while True:
        result=[]
        for i in range(n):
            try:
                a=next(iterable)
            except StopIteration:
                break
            else:
                result.append(a)
        if result:
            yield result
        else:
            break

g1=(i*i for i in range(10))
g2=chunks(g1,3)
print g2
'<generator object chunks at 0x0337B9B8>'
print list(g2)
'[[0, 1, 4], [9, 16, 25], [36, 49, 64], [81]]'
4
robert king

Utiliser les compréhensions de liste:

l = [1,2,3,4,5,6,7,8,9,10,11,12]
k = 5 #chunk size
print [Tuple(l[x:y]) for (x, y) in [(x, x+k) for x in range(0, len(l), k)]]
4
Saksham Varma

Je me rends compte que cette question est ancienne (elle est tombée sur Google), mais quelque chose comme la suivante est bien plus simple et clair que toutes les énormes suggestions complexes et utilise uniquement le découpage en tranches:

def chunker(iterable, chunksize):
    for i,c in enumerate(iterable[::chunksize]):
        yield iterable[i*chunksize:(i+1)*chunksize]

>>> for chunk in chunker(range(0,100), 10):
...     print list(chunk)
... 
[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]
... etc ...
4
user1628890

Selon cette réponse , la réponse votée par le plus grand nombre laisse un "runt" à la fin. Voici ma solution pour obtenir des morceaux de la taille la plus égale possible, sans runts. Il essaie fondamentalement de choisir exactement le point fractionnaire où il devrait diviser la liste, mais l'arrondit simplement à l'entier le plus proche:

from __future__ import division  # not needed in Python 3
def n_even_chunks(l, n):
    """Yield n as even chunks as possible from l."""
    last = 0
    for i in range(1, n+1):
        cur = int(round(i * (len(l) / n)))
        yield l[last:cur]
        last = cur

Manifestation:

>>> pprint.pprint(list(n_even_chunks(list(range(100)), 9)))
[[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, 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]]
>>> pprint.pprint(list(n_even_chunks(list(range(100)), 11)))
[[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, 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]]

Comparez à la réponse chunks la plus votée:

>>> pprint.pprint(list(chunks(list(range(100)), 100//9)))
[[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, 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]]
>>> pprint.pprint(list(chunks(list(range(100)), 100//11)))
[[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, 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]]
4
Claudiu

J'ai écrit une petite bibliothèque spécialement à cet effet, disponible ici . La fonction chunked de la bibliothèque est particulièrement efficace, car elle est implémentée en tant que générateur , ce qui permet de sauvegarder une quantité de mémoire importante dans certaines situations. De plus, il ne repose pas sur la notation de tranche, de sorte que tout itérateur arbitraire peut être utilisé.

import iterlib

print list(iterlib.chunked(xrange(1, 1000), 10))
# prints [(1, 2, 3, 4, 5, 6, 7, 8, 9, 10), (11, 12, 13, 14, 15, 16, 17, 18, 19, 20), ...]
3
rectangletangle

laisser r être la taille du bloc et L être la liste initiale, vous pouvez le faire.

chunkL = [ [i for i in L[r*k:r*(k+1)] ] for k in range(len(L)/r)] 
3
Be Wake Pandey

J'ai une solution ci-dessous qui fonctionne, mais quelques commentaires sur d'autres approches sont plus importants que cette solution. Premièrement, une bonne solution ne devrait pas nécessiter une seule boucle dans l'ordre des sous-itérateurs. Si je cours

g = paged_iter(list(range(50)), 11))
i0 = next(g)
i1 = next(g)
list(i1)
list(i0)

La sortie appropriée pour la dernière commande est

 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

ne pas

 []

Comme la plupart des solutions basées sur itertools, reviennent ici. Ce n'est pas seulement la restriction ennuyeuse habituelle sur l'accès aux itérateurs dans l'ordre. Imaginez un consommateur essayant de nettoyer des données mal entrées qui inversent l’ordre approprié des blocs de 5, c’est-à-dire que les données ressemblent à [B5, A5, D5, C5] et devraient ressembler à [A5, B5, C5, D5] (où A5 est juste cinq éléments pas une sous-liste). Ce consommateur examinerait le comportement allégué de la fonction de regroupement et n'hésiterait pas à écrire une boucle telle que

i = 0
out = []
for it in paged_iter(data,5)
    if (i % 2 == 0):
         swapped = it
    else: 
         out += list(it)
         out += list(swapped)
    i = i + 1

Cela produira des résultats mystérieusement faux si vous supposez sournoisement que les sous-itérateurs sont toujours pleinement utilisés dans l’ordre. Cela devient encore pire si vous voulez entrelacer des éléments des morceaux.

Deuxièmement, un nombre décent des solutions suggérées reposent implicitement sur le fait que les itérateurs ont un ordre déterministe (ils ne sont pas définis, par exemple) et que certaines des solutions utilisant islice peuvent convenir, cela me préoccupe.

Troisièmement, l’approche du groupeur itertools fonctionne, mais la recette s’appuie sur le comportement interne des fonctions Zip_longest (ou Zip) qui ne fait pas partie de leur comportement publié. En particulier, la fonction de groupeur ne fonctionne que parce que dans Zip_longest (i0 ... in), la fonction suivante est toujours appelée dans l'ordre suivant (i0), suivant (i1), ... suivant (in) avant de recommencer. Lorsque le groupeur transmet n copies du même objet itérateur, il repose sur ce comportement.

Enfin, bien que la solution ci-dessous puisse être améliorée si vous faites l’hypothèse critiquée ci-dessus, les sous-itérateurs sont consultés dans l’ordre et lus entièrement sans cette hypothèse, il FAUT obligatoirement (via la chaîne d’appel) ou explicitement (via deques ou une autre structure de données). pour chaque sous-critère quelque part. Donc, ne perdez pas votre temps à perdre du temps (comme je le faisais) en supposant que l’on puisse contourner cela avec une astuce intelligente.

def paged_iter(iterat, n):
    itr = iter(iterat)
    deq = None
    try:
        while(True):
            deq = collections.deque(maxlen=n)
            for q in range(n):
                deq.append(next(itr))
            yield (i for i in deq)
    except StopIteration:
        yield (i for i in deq)
3
Peter Gerdes

La réponse ci-dessus (par koffein) a un petit problème: la liste est toujours divisée en un nombre égal de divisions, pas un nombre égal d'éléments par partition. Ceci est ma version. Le "// chs + 1" prend en compte le fait que le nombre d'éléments peut ne pas être divisible exactement par la taille de la partition. La dernière partition ne sera donc que partiellement remplie.

# Given 'l' is your list

chs = 12 # Your chunksize
partitioned = [ l[i*chs:(i*chs)+chs] for i in range((len(l) // chs)+1) ]
3
Flo

Je ne pense pas avoir vu cette option, alors juste pour en ajouter une autre :)):

def chunks(iterable, chunk_size):
  i = 0;
  while i < len(iterable):
    yield iterable[i:i+chunk_size]
    i += chunk_size
3
George B

Voici une idée utilisant itertools.groupby:

def chunks(l, n):
    c = itertools.count()
    return (it for _, it in itertools.groupby(l, lambda x: next(c)//n))

Cela retourne un générateur de générateurs. Si vous voulez une liste de listes, remplacez simplement la dernière ligne par

    return [list(it) for _, it in itertools.groupby(l, lambda x: next(c)//n)]

Exemple de liste de retour:

>>> chunks('abcdefghij', 4)
[['a', 'b', 'c', 'd'], ['e', 'f', 'g', 'h'], ['i', 'j']]

(Donc oui, cela souffre du "problème de runt", qui peut ou peut ne pas être un problème dans une situation donnée.)

3
itub
def chunk(lst):
    out = []
    for x in xrange(2, len(lst) + 1):
        if not len(lst) % x:
            factor = len(lst) / x
            break
    while lst:
        out.append([lst.pop(0) for x in xrange(factor)])
    return out
3
J.T. Hurley
>>> f = lambda x, n, acc=[]: f(x[n:], n, acc+[(x[:n])]) if x else acc
>>> f("Hallo Welt", 3)
['Hal', 'lo ', 'Wel', 't']
>>> 

Si vous êtes entre parenthèses - j'ai pris un livre sur Erlang :)

3
hcvst

Pas de magie, mais simple et correct:

def chunks(iterable, n):
    """Yield successive n-sized chunks from iterable."""
    values = []
    for i, item in enumerate(iterable, 1):
        values.append(item)
        if i % n == 0:
            yield values
            values = []
    if values:
        yield values
2
guyskk

Je suis venu à la solution suivante sans création d'objet de liste temorary, qui devrait fonctionner avec n'importe quel objet itérable. Veuillez noter que cette version pour Python 2.x:

def chunked(iterable, size):
    stop = []
    it = iter(iterable)
    def _next_chunk():
        try:
            for _ in xrange(size):
                yield next(it)
        except StopIteration:
            stop.append(True)
            return

    while not stop:
        yield _next_chunk()

for it in chunked(xrange(16), 4):
   print list(it)

Sortie:

[0, 1, 2, 3]
[4, 5, 6, 7]
[8, 9, 10, 11]
[12, 13, 14, 15] 
[]

Comme vous pouvez le voir si len (iterable)% size == 0, nous avons un objet itérateur vide supplémentaire. Mais je ne pense pas que ce soit un gros problème.

2
Mikhail Lyundin
  • Fonctionne avec n'importe quel iterable
  • Les données internes sont un objet générateur (pas une liste)
  • Bon mot
 Dans [259]: get_in_chunks = lambda itr, n: (v pour _, v en g) pour _, g dans itertools.groupby (enumerate (itr), lambda (ind, _): ind/n)) 
 
 In [260]: list (list (x) pour x dans get_in_chunks (intervalle (30), 7)) 
 Out [260]: 
 [[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]]. 
2
balki

Comme @AaronHall, je suis arrivé ici à la recherche de morceaux de taille sensiblement égale. Il y a différentes interprétations de cela. Dans mon cas, si la taille souhaitée est N, je voudrais que chaque groupe ait une taille> = N. Ainsi, les orphelins créés dans la plupart des cas mentionnés ci-dessus devraient être redistribués à d'autres groupes.

Cela peut être fait en utilisant:

def nChunks(l, n):
    """ Yield n successive chunks from l.
    Works for lists,  pandas dataframes, etc
    """
    newn = int(1.0 * len(l) / n + 0.5)
    for i in xrange(0, n-1):
        yield l[i*newn:i*newn+newn]
    yield l[n*newn-newn:]

(de diviser une liste de N parties de longueur approximativement égale ) en l'appelant simplement sous la forme nChunks (l, l/n) ou nChunks (l, floor (l/n))

2
CPBL

Comme je devais faire quelque chose comme ça, voici ma solution étant donné un générateur et une taille de lot:

def pop_n_elems_from_generator(g, n):
    elems = []
    try:
        for idx in xrange(0, n):
            elems.append(g.next())
        return elems
    except StopIteration:
        return elems
2
Evan Zamir

Pas exactement pareil mais toujours gentil

def chunks(l, chunks):
    return Zip(*[iter(l)]*chunks)

l = range(1, 1000)
print chunks(l, 10) -> [ ( 1..10 ), ( 11..20 ), .., ( 991..999 ) ]
2
Moss

Cela fonctionne en v2/v3, est insérable, basé sur un générateur et utilise uniquement la bibliothèque standard:

import itertools
def split_groups(iter_in, group_size):
    return ((x for _, x in item) for _, item in itertools.groupby(enumerate(iter_in), key=lambda x: x[0] // group_size))
1
Andrey Cizov

Je n'aime pas l'idée de scinder des éléments par taille de morceau, par exemple. Le script peut diviser 101 à 3 morceaux comme [50, 50, 1]. Pour mes besoins, j'avais besoin de diviser proportionnellement et de maintenir l'ordre. J'ai d'abord écrit mon propre script, qui fonctionne bien et qui est très simple. Mais j'ai vu plus tard cette réponse , où le script est meilleur que le mien, je le recommande. Voici mon script:

def proportional_dividing(N, n):
    """
    N - length of array (bigger number)
    n - number of chunks (smaller number)
    output - arr, containing N numbers, diveded roundly to n chunks
    """
    arr = []
    if N == 0:
        return arr
    Elif n == 0:
        arr.append(N)
        return arr
    r = N // n
    for i in range(n-1):
        arr.append(r)
    arr.append(N-r*(n-1))

    last_n = arr[-1]
    # last number always will be r <= last_n < 2*r
    # when last_n == r it's ok, but when last_n > r ...
    if last_n > r:
        # ... and if difference too big (bigger than 1), then
        if abs(r-last_n) > 1:
            #[2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 7] # N=29, n=12
            # we need to give unnecessary numbers to first elements back
            diff = last_n - r
            for k in range(diff):
                arr[k] += 1
            arr[-1] = r
            # and we receive [3, 3, 3, 3, 3, 2, 2, 2, 2, 2, 2, 2]
    return arr

def split_items(items, chunks):
    arr = proportional_dividing(len(items), chunks)
    splitted = []
    for chunk_size in arr:
        splitted.append(items[:chunk_size])
        items = items[chunk_size:]
    print(splitted)
    return splitted

items = [1,2,3,4,5,6,7,8,9,10,11]
chunks = 3
split_items(items, chunks)
split_items(['a','b','c','d','e','f','g','h','i','g','k','l', 'm'], 3)
split_items(['a','b','c','d','e','f','g','h','i','g','k','l', 'm', 'n'], 3)
split_items(range(100), 4)
split_items(range(99), 4)
split_items(range(101), 4)

et sortie:

[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11]]
[['a', 'b', 'c', 'd'], ['e', 'f', 'g', 'h'], ['i', 'g', 'k', 'l', 'm']]
[['a', 'b', 'c', 'd', 'e'], ['f', 'g', 'h', 'i', 'g'], ['k', 'l', 'm', 'n']]
[range(0, 25), range(25, 50), range(50, 75), range(75, 100)]
[range(0, 25), range(25, 50), range(50, 75), range(75, 99)]
[range(0, 25), range(25, 50), range(50, 75), range(75, 101)]
1
Arthur Sult

le package python pydash pourrait être un bon choix.

from pydash.arrays import chunk
ids = ['22', '89', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '1']
chunk_ids = chunk(ids,5)
print(chunk_ids)
# output: [['22', '89', '2', '3', '4'], ['5', '6', '7', '8', '9'], ['10', '11', '1']]

pour plus de paiement liste de morceaux pydash

0
Ravi Anand

Version de chargement paresseux

import pprint
pprint.pprint(list(chunks(range(10, 75), 10)))
[range(10, 20),
 range(20, 30),
 range(30, 40),
 range(40, 50),
 range(50, 60),
 range(60, 70),
 range(70, 75)]

Conférer le résultat de cette implémentation avec l'exemple de résultat d'utilisation de réponse acceptée .

Bon nombre des fonctions ci-dessus supposent que la longueur de la totalité de l'itérable est connue à l'avance, ou du moins qu’elle est peu coûteuse à calculer.

Pour certains objets en flux, cela signifie que vous devez d'abord charger l'intégralité des données dans la mémoire (par exemple, pour télécharger l'intégralité du fichier) afin d'obtenir les informations de longueur.

Si toutefois vous ne connaissez pas encore la taille complète, vous pouvez utiliser ce code à la place:

def chunks(iterable, size):
    """
    Yield successive chunks from iterable, being `size` long.

    https://stackoverflow.com/a/55776536/3423324
    :param iterable: The object you want to split into pieces.
    :param size: The size each of the resulting pieces should have.
    """
    i = 0
    while True:
        sliced = iterable[i:i + size]
        if len(sliced) == 0:
            # to suppress stuff like `range(max, max)`.
            break
        # end if
        yield sliced
        if len(sliced) < size:
            # our slice is not the full length, so we must have passed the end of the iterator
            break
        # end if
        i += size  # so we start the next chunk at the right place.
    # end while
# end def

Cela fonctionne parce que la commande slice retournera moins/aucun élément si vous avez passé la fin d'un itérable:

"abc"[0:2] == 'ab'
"abc"[2:4] == 'c'
"abc"[4:6] == ''

Nous utilisons maintenant le résultat de la tranche et calculons la longueur de ce bloc généré. S'il est inférieur à ce que nous attendons, nous savons que nous pouvons mettre fin à l'itération.

De cette façon, l'itérateur ne sera exécuté que si vous y avez accès.

0
luckydonald

Cette question me rappelle la méthode Perl 6 .comb(n). Il décompose les chaînes en morceaux de taille n. (Il y a plus que ça, mais je vais laisser de côté les détails.)

Il est assez facile d'implémenter une fonction similaire dans Python3 en tant qu'expression lambda:

comb = lambda s,n: (s[i:i+n] for i in range(0,len(s),n))

Ensuite, vous pouvez l'appeler comme ceci:

some_list = list(range(0, 20))  # creates a list of 20 elements
generator = comb(some_list, 4)  # creates a generator that will generate lists of 4 elements
for sublist in generator:
    print(sublist)  # prints a sublist of four elements, as it's generated

Bien entendu, il n'est pas nécessaire d'affecter le générateur à une variable. vous pouvez simplement passer dessus directement comme ceci:

for sublist in comb(some_list, 4):
    print(sublist)  # prints a sublist of four elements, as it's generated

En prime, cette fonction comb() fonctionne également sur les chaînes:

list( comb('catdogant', 3) )  # returns ['cat', 'dog', 'ant']
0
J-L

Si vous ne vous souciez pas de la commande:

> from itertools import groupby
> batch_no = 3
> data = 'abcdefgh'

> [
    [x[1] for x in x[1]] 
    for x in 
    groupby(
      sorted(
        (x[0] % batch_no, x[1]) 
        for x in 
        enumerate(data)
      ),
      key=lambda x: x[0]
    )
  ]

[['a', 'd', 'g'], ['b', 'e', 'h'], ['c', 'f']]

Cette solution ne génère pas d'ensembles de même taille, mais distribue des valeurs afin que les lots soient aussi gros que possible tout en conservant le nombre de lots générés.

0
ajaest

Vous pouvez utiliser Dask pour scinder une liste en morceaux de taille égale. Dask présente l'avantage supplémentaire de conserver la mémoire, ce qui est préférable pour les très grandes données. Pour de meilleurs résultats, vous devez charger votre liste directement dans une structure de données dask afin de conserver la mémoire si votre liste est très volumineuse. En fonction de ce que vous voulez faire avec les listes, Dask dispose d'une API complète de fonctions que vous pouvez utiliser: http://docs.dask.org/en/latest/dataframe-api.html

import pandas as pd
import dask.dataframe as dd 

split = 4
my_list = range(100)
df = dd.from_pandas(pd.DataFrame(my_list), npartitions = split)
my_list = [ df.get_partition(n).compute().iloc[:,0].tolist() for n in range(split) ]

# [[1,2,3,..],[26,27,28...],[51,52,53...],[76,77,78...]]
0
Mott The Tuple