J'ai un script Python qui prend en entrée une liste d'entiers que je dois utiliser avec quatre entiers à la fois. Malheureusement, je n'ai pas le contrôle de l'entrée ou je l'aurais transmise sous forme de liste de tuples à quatre éléments. Actuellement, je le répète de cette façon:
for i in xrange(0, len(ints), 4):
# dummy op for example code
foo += ints[i] * ints[i + 1] + ints[i + 2] * ints[i + 3]
Cela ressemble beaucoup à "C-think", cependant, ce qui me laisse supposer qu'il existe un moyen plus pythonique de gérer cette situation. La liste est supprimée après itération, elle n'a donc pas besoin d'être conservée. Peut-être que quelque chose comme ça serait mieux?
while ints:
foo += ints[0] * ints[1] + ints[2] * ints[3]
ints[0:4] = []
Vous n'avez toujours pas l'impression que vous avez raison. : - /
Question associée: Comment divisez-vous une liste en morceaux de taille égale en Python?
Modifié à partir de la section recettes de python itertools docs:
from itertools import izip_longest
def grouper(iterable, n, fillvalue=None):
args = [iter(iterable)] * n
return izip_longest(*args, fillvalue=fillvalue)
Exemple
En pseudo-code pour garder l'exemple concis.
grouper('ABCDEFG', 3, 'x') --> 'ABC' 'DEF' 'Gxx'
Remarque:izip_longest
est une nouveauté de Python 2.6. En Python 3, utilisez Zip_longest
.
def chunker(seq, size):
return (seq[pos:pos + size] for pos in range(0, len(seq), size))
# (in python 2 use xrange() instead of range() to avoid allocating a list)
Simple. Facile. Vite. Fonctionne avec n'importe quelle séquence:
text = "I am a very, very helpful text"
for group in chunker(text, 7):
print repr(group),
# 'I am a ' 'very, v' 'ery hel' 'pful te' 'xt'
print '|'.join(chunker(text, 10))
# I am a ver|y, very he|lpful text
animals = ['cat', 'dog', 'rabbit', 'duck', 'bird', 'cow', 'gnu', 'fish']
for group in chunker(animals, 3):
print group
# ['cat', 'dog', 'rabbit']
# ['duck', 'bird', 'cow']
# ['gnu', 'fish']
Je suis fan de
chunkSize= 4
for i in xrange(0, len(ints), chunkSize):
chunk = ints[i:i+chunkSize]
# process chunk of size <= chunkSize
import itertools
def chunks(iterable,size):
it = iter(iterable)
chunk = Tuple(itertools.islice(it,size))
while chunk:
yield chunk
chunk = Tuple(itertools.islice(it,size))
# though this will throw ValueError if the length of ints
# isn't a multiple of four:
for x1,x2,x3,x4 in chunks(ints,4):
foo += x1 + x2 + x3 + x4
for chunk in chunks(ints,4):
foo += sum(chunk)
Autrement:
import itertools
def chunks2(iterable,size,filler=None):
it = itertools.chain(iterable,itertools.repeat(filler,size-1))
chunk = Tuple(itertools.islice(it,size))
while len(chunk) == size:
yield chunk
chunk = Tuple(itertools.islice(it,size))
# x2, x3 and x4 could get the value 0 if the length is not
# a multiple of 4.
for x1,x2,x3,x4 in chunks2(ints,4,0):
foo += x1 + x2 + x3 + x4
from itertools import izip_longest
def chunker(iterable, chunksize, filler):
return izip_longest(*[iter(iterable)]*chunksize, fillvalue=filler)
J'avais besoin d'une solution qui fonctionnerait également avec des ensembles et des générateurs. Je ne pouvais rien proposer de très court et joli, mais c'est assez lisible au moins.
def chunker(seq, size):
res = []
for el in seq:
res.append(el)
if len(res) == size:
yield res
res = []
if res:
yield res
Liste:
>>> list(chunker([i for i in range(10)], 3))
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
Ensemble:
>>> list(chunker(set([i for i in range(10)]), 3))
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
Générateur:
>>> list(chunker((i for i in range(10)), 3))
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
La solution idéale à ce problème fonctionne avec des itérateurs (pas seulement des séquences). Cela devrait aussi être rapide.
Voici la solution fournie par la documentation pour itertools:
def grouper(n, iterable, fillvalue=None):
#"grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
args = [iter(iterable)] * n
return itertools.izip_longest(fillvalue=fillvalue, *args)
En utilisant le %timeit
d'ipython sur mon livre Mac, je reçois 47,5 us par boucle.
Cependant, cela ne fonctionne vraiment pas pour moi car les résultats sont complétés pour former des groupes de taille égale. Une solution sans rembourrage est légèrement plus compliquée. La solution la plus naïve pourrait être:
def grouper(size, iterable):
i = iter(iterable)
while True:
out = []
try:
for _ in range(size):
out.append(i.next())
except StopIteration:
yield out
break
yield out
Simple, mais assez lent: 693 us par boucle
La meilleure solution que je puisse trouver utilise islice
pour la boucle interne:
def grouper(size, iterable):
it = iter(iterable)
while True:
group = Tuple(itertools.islice(it, None, size))
if not group:
break
yield group
Avec le même jeu de données, je reçois 305 us par boucle.
Impossible d'obtenir une solution pure plus rapidement que cela, je présente la solution suivante avec une mise en garde importante: si vos données d'entrée contiennent des instances de filldata
, vous risquez d'obtenir une réponse erronée.
def grouper(n, iterable, fillvalue=None):
#"grouper(3, 'ABCDEFG', 'x') --> ABC DEF Gxx"
args = [iter(iterable)] * n
for i in itertools.izip_longest(fillvalue=fillvalue, *args):
if Tuple(i)[-1] == fillvalue:
yield Tuple(v for v in i if v != fillvalue)
else:
yield i
Je n'aime vraiment pas cette réponse, mais c'est beaucoup plus rapide. 124 nous par boucle
Utiliser map () au lieu de Zip () corrige le problème de remplissage dans la réponse de J.F. Sebastian:
>>> def chunker(iterable, chunksize):
... return map(None,*[iter(iterable)]*chunksize)
Exemple:
>>> s = '1234567890'
>>> chunker(s, 3)
[('1', '2', '3'), ('4', '5', '6'), ('7', '8', '9'), ('0', None, None)]
>>> chunker(s, 4)
[('1', '2', '3', '4'), ('5', '6', '7', '8'), ('9', '0', None, None)]
>>> chunker(s, 5)
[('1', '2', '3', '4', '5'), ('6', '7', '8', '9', '0')]
Semblable à d'autres propositions, mais pas exactement identique, j'aime bien le faire, car c'est simple et facile à lire:
it = iter([1, 2, 3, 4, 5, 6, 7, 8, 9])
for chunk in Zip(it, it, it, it):
print chunk
>>> (1, 2, 3, 4)
>>> (5, 6, 7, 8)
De cette façon, vous n'obtiendrez pas le dernier morceau partiel. Si vous voulez obtenir (9, None, None, None)
comme dernier morceau, utilisez simplement izip_longest
à partir de itertools
.
Puisque personne n'en a encore parlé, voici une solution Zip()
:
>>> def chunker(iterable, chunksize):
... return Zip(*[iter(iterable)]*chunksize)
Cela ne fonctionne que si la longueur de votre séquence est toujours divisible par la taille du bloc ou si vous ne vous souciez pas du dernier.
Exemple:
>>> s = '1234567890'
>>> chunker(s, 3)
[('1', '2', '3'), ('4', '5', '6'), ('7', '8', '9')]
>>> chunker(s, 4)
[('1', '2', '3', '4'), ('5', '6', '7', '8')]
>>> chunker(s, 5)
[('1', '2', '3', '4', '5'), ('6', '7', '8', '9', '0')]
Ou utilisez itertools.izip pour retourner un itérateur au lieu d'une liste:
>>> from itertools import izip
>>> def chunker(iterable, chunksize):
... return izip(*[iter(iterable)]*chunksize)
Le rembourrage peut être corrigé avec La réponse de @ ΤΖΩΤΖΙΟΥ :
>>> from itertools import chain, izip, repeat
>>> def chunker(iterable, chunksize, fillvalue=None):
... it = chain(iterable, repeat(fillvalue, chunksize-1))
... args = [it] * chunksize
... return izip(*args)
Si cela ne vous dérange pas d'utiliser un paquet externe, vous pouvez utiliser iteration_utilities.grouper
from iteration_utilties
1. Il supporte tous les iterables (pas seulement les séquences):
from iteration_utilities import grouper
seq = list(range(20))
for group in grouper(seq, 4):
print(group)
qui imprime:
(0, 1, 2, 3)
(4, 5, 6, 7)
(8, 9, 10, 11)
(12, 13, 14, 15)
(16, 17, 18, 19)
Si la longueur n'est pas un multiple de la taille du groupe, elle prend également en charge le remplissage (dernier groupe incomplet) ou la troncature (suppression du dernier groupe incomplet):
from iteration_utilities import grouper
seq = list(range(17))
for group in grouper(seq, 4):
print(group)
# (0, 1, 2, 3)
# (4, 5, 6, 7)
# (8, 9, 10, 11)
# (12, 13, 14, 15)
# (16,)
for group in grouper(seq, 4, fillvalue=None):
print(group)
# (0, 1, 2, 3)
# (4, 5, 6, 7)
# (8, 9, 10, 11)
# (12, 13, 14, 15)
# (16, None, None, None)
for group in grouper(seq, 4, truncate=True):
print(group)
# (0, 1, 2, 3)
# (4, 5, 6, 7)
# (8, 9, 10, 11)
# (12, 13, 14, 15)
1 Disclaimer: Je suis l'auteur de ce paquet.
Utiliser de petites fonctions et des choses ne m'intéresse pas vraiment; Je préfère simplement utiliser des tranches:
data = [...]
chunk_size = 10000 # or whatever
chunks = [data[i:i+chunk_size] for i in xrange(0,len(data),chunk_size)]
for chunk in chunks:
...
Si la liste est longue, la méthode la plus performante consiste à utiliser un générateur:
def get_chunk(iterable, chunk_size):
result = []
for item in iterable:
result.append(item)
if len(result) == chunk_size:
yield Tuple(result)
result = []
if len(result) > 0:
yield Tuple(result)
for x in get_chunk([1,2,3,4,5,6,7,8,9,10], 3):
print x
(1, 2, 3)
(4, 5, 6)
(7, 8, 9)
(10,)
Avec NumPy, c'est simple:
ints = array([1, 2, 3, 4, 5, 6, 7, 8])
for int1, int2 in ints.reshape(-1, 2):
print(int1, int2)
sortie:
1 2
3 4
5 6
7 8
Une autre approche consisterait à utiliser la forme à deux arguments de iter
:
from itertools import islice
def group(it, size):
it = iter(it)
return iter(lambda: Tuple(islice(it, size)), ())
Ceci peut être facilement adapté pour utiliser un rembourrage (similaire à Markus Jarderot ’s (s)):
from itertools import islice, chain, repeat
def group_pad(it, size, pad=None):
it = chain(iter(it), repeat(pad))
return iter(lambda: Tuple(islice(it, size)), (pad,) * size)
Ceux-ci peuvent même être combinés pour un remplissage optionnel:
_no_pad = object()
def group(it, size, pad=_no_pad):
if pad == _no_pad:
it = iter(it)
sentinel = ()
else:
it = chain(iter(it), repeat(pad))
sentinel = (pad,) * size
return iter(lambda: Tuple(islice(it, size)), sentinel)
À moins que quelque chose me manque, la solution simple suivante avec des expressions de générateur n'a pas été mentionnée. Il suppose que la taille et le nombre de morceaux sont connus (ce qui est souvent le cas), et qu'aucun remplissage n'est requis:
def chunks(it, n, m):
"""Make an iterator over m first chunks of size n.
"""
it = iter(it)
# Chunks are presented as tuples.
return (Tuple(next(it) for _ in range(n)) for _ in range(m))
Voici un chunker sans importations prenant en charge les générateurs:
def chunks(seq, size):
it = iter(seq)
while True:
ret = Tuple(it.next() for _ in range(size))
if len(ret) == size:
yield ret
else:
raise StopIteration()
Exemple d'utilisation:
>>> def foo():
... i = 0
... while True:
... i += 1
... yield i
...
>>> c = chunks(foo(), 3)
>>> c.next()
(1, 2, 3)
>>> c.next()
(4, 5, 6)
>>> list(chunks('abcdefg', 2))
[('a', 'b'), ('c', 'd'), ('e', 'f')]
def chunker(iterable, n):
"""Yield iterable in chunk sizes.
>>> chunks = chunker('ABCDEF', n=4)
>>> chunks.next()
['A', 'B', 'C', 'D']
>>> chunks.next()
['E', 'F']
"""
it = iter(iterable)
while True:
chunk = []
for i in range(n):
try:
chunk.append(it.next())
except StopIteration:
yield chunk
raise StopIteration
yield chunk
if __== '__main__':
import doctest
doctest.testmod()
A propos de la solution donnée par J.F. Sebastian
ici :
def chunker(iterable, chunksize):
return Zip(*[iter(iterable)]*chunksize)
C'est intelligent, mais a un inconvénient: retournez toujours Tuple. Comment obtenir de la ficelle à la place?
Bien sûr, vous pouvez écrire ''.join(chunker(...))
, mais le Tuple temporaire est quand même construit.
Vous pouvez vous débarrasser du tuple temporaire en écrivant Zip
, comme ceci:
class IteratorExhausted(Exception):
pass
def translate_StopIteration(iterable, to=IteratorExhausted):
for i in iterable:
yield i
raise to # StopIteration would get ignored because this is generator,
# but custom exception can leave the generator.
def custom_Zip(*iterables, reductor=Tuple):
iterators = Tuple(map(translate_StopIteration, iterables))
while True:
try:
yield reductor(next(i) for i in iterators)
except IteratorExhausted: # when any of iterators get exhausted.
break
Ensuite
def chunker(data, size, reductor=Tuple):
return custom_Zip(*[iter(data)]*size, reductor=reductor)
Exemple d'utilisation:
>>> for i in chunker('12345', 2):
... print(repr(i))
...
('1', '2')
('3', '4')
>>> for i in chunker('12345', 2, ''.join):
... print(repr(i))
...
'12'
'34'
Je ne veux jamais que mes morceaux soient rembourrés, cette exigence est donc essentielle. Je trouve que la capacité de travailler sur n'importe quelle itération est également une exigence. Compte tenu de cela, j'ai décidé d'étendre la réponse acceptée, https://stackoverflow.com/a/434411/1074659 .
Les performances pèsent légèrement sur cette approche si le remplissage n’est pas souhaité en raison de la nécessité de comparer et de filtrer les valeurs remplies. Cependant, pour les gros morceaux, cet utilitaire est très performant.
#!/usr/bin/env python3
from itertools import Zip_longest
_UNDEFINED = object()
def chunker(iterable, chunksize, fillvalue=_UNDEFINED):
"""
Collect data into chunks and optionally pad it.
Performance worsens as `chunksize` approaches 1.
Inspired by:
https://docs.python.org/3/library/itertools.html#itertools-recipes
"""
args = [iter(iterable)] * chunksize
chunks = Zip_longest(*args, fillvalue=fillvalue)
yield from (
filter(lambda val: val is not _UNDEFINED, chunk)
if chunk[-1] is _UNDEFINED
else chunk
for chunk in chunks
) if fillvalue is _UNDEFINED else chunks
def group_by(iterable, size):
"""Group an iterable into lists that don't exceed the size given.
>>> group_by([1,2,3,4,5], 2)
[[1, 2], [3, 4], [5]]
"""
sublist = []
for index, item in enumerate(iterable):
if index > 0 and index % size == 0:
yield sublist
sublist = []
sublist.append(item)
if sublist:
yield sublist
Dans votre deuxième méthode, je passerais au groupe de 4 suivant en procédant ainsi:
ints = ints[4:]
Cependant, comme je n’ai fait aucune mesure de la performance, je ne sais pas laquelle pourrait être plus efficace.
Cela dit, je choisirais généralement la première méthode. Ce n'est pas beau, mais c'est souvent une conséquence de l'interface avec le monde extérieur.
Vous pouvez utiliser partition ou chunks function from funcy library:
from funcy import partition
for a, b, c, d in partition(4, ints):
foo += a * b * c * d
Ces fonctions ont également les versions d'itérateur ipartition
et ichunks
, qui seront plus efficaces dans ce cas.
Vous pouvez également jeter un œil à leur mise en œuvre .
J'aime cette approche. Il se sent simple et pas magique, supporte tous les types itérables et ne nécessite pas d’importation.
def chunk_iter(iterable, chunk_size):
it = iter(iterable)
while True:
chunk = Tuple(next(it) for _ in range(chunk_size))
if not chunk:
break
yield chunk
Encore une autre réponse, dont les avantages sont:
1) facilement compréhensible
2) Fonctionne sur n’importe quelle séquence, pas seulement des séquences (certaines des réponses ci-dessus vont s’étouffer avec les poignées de fichiers)
3) Ne charge pas le bloc en mémoire en une fois
4) Ne fait pas une longue liste de références au même itérateur en mémoire
5) Pas de remplissage des valeurs de remplissage à la fin de la liste
Cela étant dit, je n'ai pas chronométré le temps, ce qui pourrait être plus lent que certaines des méthodes les plus intelligentes, et certains des avantages pourraient ne pas être pertinents compte tenu du cas d'utilisation.
def chunkiter(iterable, size):
def inneriter(first, iterator, size):
yield first
for _ in xrange(size - 1):
yield iterator.next()
it = iter(iterable)
while True:
yield inneriter(it.next(), it, size)
In [2]: i = chunkiter('abcdefgh', 3)
In [3]: for ii in i:
for c in ii:
print c,
print ''
...:
a b c
d e f
g h
Mettre à jour:
Quelques inconvénients dus au fait que les boucles interne et externe extraient des valeurs du même itérateur:
1) continue ne fonctionne pas comme prévu dans la boucle externe - il continue simplement à l'élément suivant au lieu de sauter un bloc. Cependant, cela ne semble pas être un problème car il n’ya rien à tester dans la boucle externe.
2) break ne fonctionne pas comme prévu dans la boucle interne - le contrôle se retrouvera dans la boucle interne avec le prochain élément de l'itérateur. Pour ignorer des morceaux entiers, enveloppez l’itérateur interne (ii ci-dessus) dans un tuple, par ex. for c in Tuple(ii)
, ou définir un indicateur et épuiser l'itérateur.
Pour éviter toutes les conversions vers une liste import itertools
et:
>>> for k, g in itertools.groupby(xrange(35), lambda x: x/10):
... list(g)
Produit:
...
0 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
1 [10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
2 [20, 21, 22, 23, 24, 25, 26, 27, 28, 29]
3 [30, 31, 32, 33, 34]
>>>
J'ai vérifié groupby
et il ne convertit pas en liste ni n'utilise len
donc je pense que cela retardera la résolution de chaque valeur jusqu'à ce qu'elle soit réellement utilisée. Malheureusement, aucune des réponses disponibles (pour le moment) ne semblait offrir cette variation.
Évidemment, si vous devez manipuler chaque élément à son tour, imbriquez une boucle for sur g:
for k,g in itertools.groupby(xrange(35), lambda x: x/10):
for i in g:
# do what you need to do with individual items
# now do what you need to do with the whole group
Mon intérêt spécifique à cet égard était la nécessité de recourir à un générateur pour soumettre des modifications allant jusqu'à 1 000 lots à l'API gmail:
messages = a_generator_which_would_not_be_smart_as_a_list
for idx, batch in groupby(messages, lambda x: x/1000):
batch_request = BatchHttpRequest()
for message in batch:
batch_request.add(self.service.users().messages().modify(userId='me', id=message['id'], body=msg_labels))
http = httplib2.Http()
self.credentials.authorize(http)
batch_request.execute(http=http)
Tout à fait Pythonic ici (vous pouvez également insérer le corps de la fonction split_groups
)
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))
for x, y, z, w in split_groups(range(16), 4):
foo += x * y + z * w
Solution ponctuelle, unipolaire, permettant de parcourir une liste x
en morceaux de taille 4
-
for a, b, c, d in Zip(x[0::4], x[1::4], x[2::4], x[3::4]):
... do something with a, b, c and d ...
Au début, je l’ai conçu pour scinder les chaînes en sous-chaînes afin d’analyser les chaînes contenant des éléments hex.
Aujourd'hui, je l'ai transformé en générateur complexe, mais toujours simple.
def chunker(iterable, size, reductor, condition):
it = iter(iterable)
def chunk_generator():
return (next(it) for _ in range(size))
chunk = reductor(chunk_generator())
while condition(chunk):
yield chunk
chunk = reductor(chunk_generator())
iterable
est un itératif/itérateur/générateur qui contient/génère/itère des données d’entrée,size
est, bien sûr, la taille du bloc que vous voulez obtenir,reductor
est un appelable, qui reçoit le générateur itérant sur le contenu du bloc.
.__ Je m'attendrais à ce qu'il retourne une séquence ou une chaîne, mais je ne l'exige pas.
Vous pouvez transmettre cet argument par exemple list
, Tuple
, set
, frozenset
,
ou n'importe quoi d'amateur. Je passerais cette fonction en retournant une chaîne
(à condition que iterable
contienne/génère/itère sur des chaînes):
def concatenate(iterable):
return ''.join(iterable)
Notez que reductor
peut provoquer la fermeture du générateur en soulevant une exception.
condition
est un appelable qui reçoit tout ce que reductor
a renvoyé.
Il décide de l’approuver et de le céder (en retournant tout ce qui évalue à True
),
.__ ou de le refuser et de terminer le travail du générateur (en renvoyant quelque chose d'autre ou en levant une exception).
Lorsque le nombre d'éléments dans iterable
n'est pas divisible par size
, lorsque it
est épuisé, reductor
recevra un générateur générant moins d'éléments que size
.
Appelons ces éléments lasts elements.
J'ai invité deux fonctions à passer comme argument:
lambda x:x
- les éléments lasts seront cédés.
lambda x: len(x)==<size>
- les éléments lasts seront rejetés.
remplacer <size>
en utilisant un nombre égal à size
Cette réponse divise une liste de chaînes , f.ex. pour atteindre la conformité de longueur de ligne PEP8:
def split(what, target_length=79):
'''splits list of strings into sublists, each
having string length at most 79'''
out = [[]]
while what:
if len("', '".join(out[-1])) + len(what[0]) < target_length:
out[-1].append(what.pop(0))
else:
if not out[-1]: # string longer than target_length
out[-1] = [what.pop(0)]
out.append([])
return out
Utilisé comme
>>> split(['deferred_income', 'long_term_incentive', 'restricted_stock_deferred', 'shared_receipt_with_poi', 'loan_advances', 'from_messages', 'other', 'director_fees', 'bonus', 'total_stock_value', 'from_poi_to_this_person', 'from_this_person_to_poi', 'restricted_stock', 'salary', 'total_payments', 'exercised_stock_options'], 75)
[['deferred_income', 'long_term_incentive', 'restricted_stock_deferred'], ['shared_receipt_with_poi', 'loan_advances', 'from_messages', 'other'], ['director_fees', 'bonus', 'total_stock_value', 'from_poi_to_this_person'], ['from_this_person_to_poi', 'restricted_stock', 'salary', 'total_payments'], ['exercised_stock_options']]
Il ne semble pas y avoir de jolie façon de faire cela. Ici est une page comportant un certain nombre de méthodes, notamment:
def split_seq(seq, size):
newseq = []
splitsize = 1.0/size*len(seq)
for i in range(size):
newseq.append(seq[int(round(i*splitsize)):int(round((i+1)*splitsize))])
return newseq
J'espère qu'en transformant un itérateur d'une liste, je ne copie pas simplement une partie de la liste. Les générateurs peuvent être découpés et ils seront toujours automatiquement générateurs, tandis que les listes seront découpées en énormes morceaux de 1000 entrées, ce qui est moins efficace.
def iter_group(iterable, batch_size:int):
length = len(iterable)
start = batch_size*-1
end = 0
while(end < length):
start += batch_size
end += batch_size
if type(iterable) == list:
yield (iterable[i] for i in range(start,min(length-1,end)))
else:
yield iterable[start:end]
Usage:
items = list(range(1,1251))
for item_group in iter_group(items, 1000):
for item in item_group:
print(item)
Si les listes ont la même taille, vous pouvez les combiner en listes de 4-tuples avec Zip()
. Par exemple:
# Four lists of four elements each.
l1 = range(0, 4)
l2 = range(4, 8)
l3 = range(8, 12)
l4 = range(12, 16)
for i1, i2, i3, i4 in Zip(l1, l2, l3, l4):
...
Voici ce que la fonction Zip()
produit:
>>> print l1
[0, 1, 2, 3]
>>> print l2
[4, 5, 6, 7]
>>> print l3
[8, 9, 10, 11]
>>> print l4
[12, 13, 14, 15]
>>> print Zip(l1, l2, l3, l4)
[(0, 4, 8, 12), (1, 5, 9, 13), (2, 6, 10, 14), (3, 7, 11, 15)]
Si les listes sont volumineuses et que vous ne souhaitez pas les combiner en une liste plus grande, utilisez itertools.izip()
, qui produit un itérateur plutôt qu'une liste.
from itertools import izip
for i1, i2, i3, i4 in izip(l1, l2, l3, l4):
...
Il est facile de faire fonctionner itertools.groupby
pour que vous obteniez un itérable d'iterables, sans créer de listes temporaires:
groupby(iterable, (lambda x,y: (lambda z: x.next()/y))(count(),100))
Ne soyez pas rebutés par les lambdas imbriqués, lambda externe ne s'exécute qu'une seule fois pour mettre le générateur count()
et la constante 100
dans la portée du lambda interne.
J'utilise cela pour envoyer des morceaux de lignes à mysql.
for k,v in groupby(bigdata, (lambda x,y: (lambda z: x.next()/y))(count(),100))):
cursor.executemany(sql, v)
Pourquoi ne pas utiliser la compréhension de liste
l = [1 , 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
n = 4
filler = 0
fills = len(l) % n
chunks = ((l + [filler] * fills)[x * n:x * n + n] for x in range(int((len(l) + n - 1)/n)))
print(chunks)
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 0]]