web-dev-qa-db-de.com

Was ist die "Pythonic" -Methode, um eine Liste in Abschnitten zu durchlaufen?

Ich habe ein Python-Skript, das eine Liste von ganzen Zahlen als Eingabe übernimmt, die ich zum Arbeiten mit vier ganzen Zahlen auf einmal verwenden muss. Leider habe ich keine Kontrolle über die Eingabe, oder ich würde sie als Liste von Tupeln mit vier Elementen übergeben. Derzeit iteriere ich so:

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]

Es sieht jedoch sehr nach "C-think" aus, was mich vermuten lässt, dass es eine eher pythonische Art gibt, mit dieser Situation umzugehen. Die Liste wird nach Iteration gelöscht und muss daher nicht beibehalten werden. Vielleicht wäre so etwas besser?

while ints:
    foo += ints[0] * ints[1] + ints[2] * ints[3]
    ints[0:4] = []

Trotzdem fühlt es sich nicht ganz richtig an. : - /

Verwandte Frage: Wie teilt man in Python eine Liste in gleich große Brocken auf?

384
Ben Blank

Aus dem Abschnitt recipes von Python's itertools docs geändert:

from itertools import izip_longest

def grouper(iterable, n, fillvalue=None):
    args = [iter(iterable)] * n
    return izip_longest(*args, fillvalue=fillvalue)

Beispiel
Im Pseudocode, um das Beispiel knapp zu halten.

grouper('ABCDEFG', 3, 'x') --> 'ABC' 'DEF' 'Gxx'

Hinweis:izip_longest ist neu in Python 2.6. In Python 3 verwenden Sie Zip_longest.

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

Einfach. Einfach. Schnell. Funktioniert mit jeder Sequenz:

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']
346
nosklo

Ich bin ein Fan von 

chunkSize= 4
for i in xrange(0, len(ints), chunkSize):
    chunk = ints[i:i+chunkSize]
    # process chunk of size <= chunkSize
98
S.Lott
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)

Ein anderer Weg:

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
21
Markus Jarderot
from itertools import izip_longest

def chunker(iterable, chunksize, filler):
    return izip_longest(*[iter(iterable)]*chunksize, fillvalue=filler)
11
Pedro Henriques

Ich brauchte eine Lösung, die auch mit Sets und Generatoren funktioniert. Ich konnte mir nichts sehr kurzes und hübsches vorstellen, aber es ist zumindest lesbar.

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

Einstellen:

>>> list(chunker(set([i for i in range(10)]), 3))
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]

Generator:

>>> list(chunker((i for i in range(10)), 3))
[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
8
bcoughlan

Die ideale Lösung für dieses Problem funktioniert mit Iteratoren (nicht nur mit Sequenzen). Es sollte auch schnell gehen.

Dies ist die Lösung aus der Dokumentation für 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)

Mit ipythons %timeit auf meinem Mac Book Air erhalte ich 47,5 us pro Schleife.

Dies funktioniert jedoch nicht wirklich für mich, da die Ergebnisse zu Gruppen in gleichgroßer Größe gepolstert werden. Eine Lösung ohne Polsterung ist etwas komplizierter. Die naivste Lösung könnte sein:

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

Einfach, aber ziemlich langsam: 693 us pro Loop

Die beste Lösung, die ich mit islice für die innere Schleife entwickeln könnte:

def grouper(size, iterable):
    it = iter(iterable)
    while True:
        group = Tuple(itertools.islice(it, None, size))
        if not group:
            break
        yield group

Mit dem gleichen Datensatz bekomme ich 305 US-Dollar pro Schleife.

Kann eine reine Lösung nicht schneller als diese erhalten werden, gebe ich die folgende Lösung mit einem wichtigen Vorbehalt: Wenn Ihre Eingabedaten Instanzen von filldata enthalten, könnten Sie eine falsche Antwort erhalten.

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

Ich mag diese Antwort wirklich nicht, aber sie ist wesentlich schneller. 124 uns pro Schleife

7
rhettg

Die Verwendung von map () anstelle von zip () behebt das Auffüllproblem in der Antwort von J. F. Sebastian:

>>> def chunker(iterable, chunksize):
...   return map(None,*[iter(iterable)]*chunksize)

Beispiel:

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

Ähnlich wie bei anderen Vorschlägen, aber nicht genau identisch, mache ich es gerne so, weil es einfach und leicht zu lesen ist:

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)

Auf diese Weise erhalten Sie nicht den letzten Teilblock. Wenn Sie (9, None, None, None) als letzten Abschnitt erhalten möchten, verwenden Sie einfach izip_longest aus itertools.

6
kriss

Da es bisher noch niemand erwähnt hat, ist hier eine Zip()-Lösung:

>>> def chunker(iterable, chunksize):
...     return Zip(*[iter(iterable)]*chunksize)

Es funktioniert nur, wenn die Länge Ihrer Sequenz immer durch die Chunk-Größe teilbar ist, oder Sie interessieren sich nicht für einen nachfolgenden Chunk, wenn dies nicht der Fall ist.

Beispiel:

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

Oder verwenden Sie itertools.izip , um einen Iterator anstelle einer Liste zurückzugeben:

>>> from itertools import izip
>>> def chunker(iterable, chunksize):
...     return izip(*[iter(iterable)]*chunksize)

Die Polsterung kann mit der Antwort von @ ΤΖΩ - korrigiert werden:

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

Wenn es Ihnen nichts ausmacht, ein externes Paket zu verwenden, können Sie iteration_utilities.grouper aus iteration_utilties verwenden. 1. Es unterstützt alle Iterables (nicht nur Sequenzen):

from iteration_utilities import grouper
seq = list(range(20))
for group in grouper(seq, 4):
    print(group)

welche druckt:

(0, 1, 2, 3)
(4, 5, 6, 7)
(8, 9, 10, 11)
(12, 13, 14, 15)
(16, 17, 18, 19)

Falls die Länge kein Vielfaches der Gruppengröße ist, unterstützt sie auch das Füllen (die unvollständige letzte Gruppe) oder das Abschneiden (Löschen der unvollständigen letzten Gruppe) der letzten:

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 Haftungsausschluss: Ich bin der Autor dieses Pakets.

4
MSeifert

Kleine Funktionen und Dinge zu benutzen, gefällt mir nicht wirklich; Ich ziehe es vor, nur Scheiben zu verwenden:

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:
    ...
3
Will

Wenn die Liste groß ist, können Sie am besten einen Generator verwenden:

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,)
3
Robert Rossney

Mit NumPy ist es einfach:

ints = array([1, 2, 3, 4, 5, 6, 7, 8])
for int1, int2 in ints.reshape(-1, 2):
    print(int1, int2)

ausgabe:

1 2
3 4
5 6
7 8
2
endolith

Ein anderer Ansatz wäre die Verwendung der Zwei-Argument-Form von iter

from itertools import islice

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

Dies kann leicht angepasst werden, um die Polsterung zu verwenden (ähnlich wie Markus Jarderot ).

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)

Diese können für optionale Polsterung sogar kombiniert werden:

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

Sofern ich nichts vermisse, wurde die folgende einfache Lösung mit Generatorausdrücken nicht erwähnt. Es wird vorausgesetzt, dass sowohl die Größe als auch die Anzahl der Chunks bekannt sind (was häufig der Fall ist) und dass keine Polsterung erforderlich ist:

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

Hier ist ein Chunker ohne Import, der Generatoren unterstützt:

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

Anwendungsbeispiel:

>>> 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')]
1
Cuadue
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()
1
ksindi

Über die Lösung gab J.F. Sebastianhier :

def chunker(iterable, chunksize):
    return Zip(*[iter(iterable)]*chunksize)

Es ist klug, hat aber einen Nachteil - immer Tuple zurückgeben. Wie bekomme ich stattdessen einen String?
Natürlich können Sie ''.join(chunker(...)) schreiben, aber das temporäre Tuple ist trotzdem konstruiert.

Sie können das temporäre Tupel loswerden, indem Sie eigene Zip schreiben, wie folgt:

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

Dann

def chunker(data, size, reductor=Tuple):
    return custom_Zip(*[iter(data)]*size, reductor=reductor)

Verwendungsbeispiel:

>>> 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'
1
GingerPlusPlus

Ich möchte nie, dass meine Brocken gefüllt sind, daher ist diese Anforderung unerlässlich. Ich finde, dass die Fähigkeit, an jedem Iterer zu arbeiten, ebenfalls erforderlich ist. Angesichts dessen habe ich mich entschlossen, die akzeptierte Antwort zu verlängern, https://stackoverflow.com/a/434411/1074659

Die Leistung ist bei diesem Ansatz ein kleiner Treffer, wenn die Auffüllung nicht gewünscht wird, da die aufgefüllten Werte verglichen und gefiltert werden müssen. Bei großen Stückgrößen ist dieses Dienstprogramm jedoch sehr leistungsfähig.

#!/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
1
frankish
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
1
Wilfred Hughes

Bei Ihrer zweiten Methode würde ich mit der folgenden Gruppe von 4 vorrücken:

ints = ints[4:]

Ich habe jedoch keine Leistungsmessung durchgeführt, daher weiß ich nicht, welche effizienter ist.

Allerdings würde ich normalerweise die erste Methode wählen. Es ist nicht schön, aber das ist oft eine Folge der Verbindung mit der Außenwelt.

1
Greg Hewgill

Sie können partition oder chunks - Funktion von funcy library verwenden:

from funcy import partition

for a, b, c, d in partition(4, ints):
    foo += a * b * c * d

Diese Funktionen haben auch die Iterator-Versionen ipartition und ichunks, die in diesem Fall effizienter sind.

Sie können auch auf deren Implementierung schauen.

1
Suor

Ich mag diesen Ansatz. Es fühlt sich einfach und nicht magisch an, unterstützt alle iterierbaren Typen und erfordert keinen Import.

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

Noch eine Antwort, deren Vorteile sind:

1) leicht verständlich
2) Funktioniert auf allen Iterationen, nicht nur auf Sequenzen (einige der obigen Antworten werden bei Dateihandles ersticken)
3) Der Block wird nicht gleichzeitig in den Speicher geladen
4) Führt keine lange Liste von Verweisen auf denselben Iterator im Speicher aus
5) Kein Auffüllen der Füllwerte am Ende der Liste

Das heißt, ich habe es nicht zeitlich festgelegt, so dass es langsamer sein könnte als einige der intelligenteren Methoden, und einige der Vorteile können angesichts des Anwendungsfalls irrelevant sein.

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 

Update:
Ein paar Nachteile aufgrund der Tatsache, dass die inneren und äußeren Schleifen Werte aus demselben Iterator ziehen:
1) continue funktioniert nicht wie erwartet in der äußeren Schleife - es wird einfach mit dem nächsten Element fortgefahren, anstatt einen Block zu überspringen. Dies scheint jedoch kein Problem zu sein, da in der äußeren Schleife nichts zu testen ist.
2) break funktioniert nicht wie erwartet in der inneren Schleife - die Steuerung wird in der inneren Schleife mit dem nächsten Element im Iterator wieder ausgeführt. Um ganze Brocken zu überspringen, wickeln Sie entweder den inneren Iterator (ii oben) in einen Tupel, z. for c in Tuple(ii), oder setzen Sie ein Flag und lassen Sie den Iterator aus.

1
elhefe

So vermeiden Sie alle Konvertierungen in eine Liste import itertools und:

>>> for k, g in itertools.groupby(xrange(35), lambda x: x/10):
...     list(g)

Produziert:

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

Ich habe groupby überprüft, und es wird nicht in Liste konvertiert oder len verwendet. Ich denke, dies wird die Auflösung jedes Wertes verzögern, bis er tatsächlich verwendet wird. Leider schien keine der verfügbaren Antworten (zu dieser Zeit) diese Variation zu bieten.

Wenn Sie jedes Element bearbeiten müssen, verschachteln Sie eine for-Schleife über 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

Mein besonderes Interesse daran war die Notwendigkeit, einen Generator zu verwenden, um Änderungen von bis zu 1000 Batches an die gmail-API zu übermitteln:

    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)
1
John Mee

Ganz Pythonic hier (Sie können auch den Körper der split_groups-Funktion einbetten)

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
0
Andrey Cizov

One-Liner, Adhoc-Lösung zum Durchlaufen einer Liste x in Chunks der Größe 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 ...
0
Tutul

Zuerst habe ich es entworfen, um Zeichenfolgen in Teilzeichenfolgen aufzuteilen, um Zeichenfolgen zu analysieren, die Hex enthalten.
Heute habe ich daraus einen komplexen, aber immer noch einfachen Generator gemacht.

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

Argumente:

Offensichtliche

  • iterable ist ein beliebiger iterierbarer Iterator/Generator, der Eingabedaten enthält/erzeugt/iteriert,
  • size ist natürlich die Größe des Blocks, den Sie erhalten möchten.

Interessanter

  • reductor ist eine aufrufbare Funktion, die einen Generator empfängt, der den Inhalt des Chunks durchläuft.
    Ich würde erwarten, dass es Sequenz oder String zurückgibt, aber ich verlange das nicht.

    Sie können als dieses Argument beispielsweise list, Tuple, set, frozenset, übergeben.
    oder etwas schicker. Ich würde diese Funktion übergeben und String zurückgeben
    (vorausgesetzt, dass iterable Strings enthält/generiert/iteriert):

    def concatenate(iterable):
        return ''.join(iterable)
    

    Beachten Sie, dass reductor das Schließen des Generators verursachen kann, indem eine Ausnahme ausgelöst wird.

  • condition ist eine aufrufbare Funktion, die alles empfängt, was von reductor zurückgegeben wurde.
    .__ beschließt, es zu genehmigen und zu erbringen (durch Rückgabe aller Bewertungen an True),
    oder es ablehnen und die Arbeit des Generators beenden (indem Sie etwas anderes zurückgeben oder eine Ausnahme auslösen).

    Wenn die Anzahl der Elemente in iterable nicht durch size teilbar ist und it erschöpft ist, erhält reductor einen Generator, der weniger Elemente als size generiert.
    Nennen wir diese Elemente lasts elements .

    Ich habe zwei Funktionen eingeladen, um dieses Argument zu übergeben: 

    • lambda x:x - die lasts-Elemente werden ausgegeben.

    • lambda x: len(x)==<size> - das lasts-Element wird abgelehnt.
      ersetzen Sie <size> mit einer Zahl, die size entspricht.

0
GingerPlusPlus

Diese Antwort teilt eine Liste von Strings auf , zB. Einhaltung der PEP8-Leitungslänge:

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

Benutzen als

>>> 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']]
0
serv-inc

Es scheint keinen schönen Weg zu geben. Hier ist eine Seite mit einer Reihe von Methoden, darunter:

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
0
Harley Holcombe

Ich hoffe, dass ich, indem ich einen Iterator aus einer Liste wende, nicht einfach ein Stück der Liste kopiere. Generatoren können in Scheiben geschnitten werden und sie werden automatisch immer noch ein Generator sein, während Listen in riesige Stücke von 1000 Einträgen geschnitten werden, was weniger effizient ist. 

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]

Verwendungszweck:

items = list(range(1,1251))

for item_group in iter_group(items, 1000):
    for item in item_group:
        print(item)
0
Ben

Wenn die Listen die gleiche Größe haben, können Sie sie mit Zip() zu Listen von 4-Tupeln kombinieren. Zum Beispiel:

# 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):
    ...

Die Funktion Zip() erzeugt Folgendes:

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

Wenn die Listen groß sind und Sie sie nicht zu einer größeren Liste zusammenfassen möchten, verwenden Sie itertools.izip(), wodurch ein Iterator anstelle einer Liste erstellt wird.

from itertools import izip

for i1, i2, i3, i4 in izip(l1, l2, l3, l4):
    ...
0
Brian Clapper

Es ist leicht, itertools.groupby dafür zu sorgen, dass Sie iterierbare Iterationen ausführen können, ohne temporäre Listen erstellen zu müssen:

groupby(iterable, (lambda x,y: (lambda z: x.next()/y))(count(),100))

Lassen Sie sich nicht von den verschachtelten Lambdas abschrecken, das äußere Lambda läuft nur einmal, um den count()-Generator und den konstanten 100 in den Bereich des inneren Lambda zu stellen.

Ich benutze dies, um Zeilen von Zeilen an mysql zu senden.

for k,v in groupby(bigdata, (lambda x,y: (lambda z: x.next()/y))(count(),100))):
    cursor.executemany(sql, v)
0
topkara

Warum nicht Listenverständnis verwenden?

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]]
0
Mohammad Azim