web-dev-qa-db-ja.com

チャンクのリストを反復処理する最も「Python的な」方法は何ですか?

整数のリストを入力として受け取るPythonスクリプトがあり、一度に4つの整数を処理する必要があります。残念ながら、入力を制御できません。または、4要素のタプルのリストとして渡されます。現在、私はそれを次のように繰り返しています:

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]

しかし、これは「C-think」によく似ているため、この状況に対処するためのPython的な方法があると思われます。リストは反復後に破棄されるため、保存する必要はありません。おそらくこのようなものの方が良いでしょうか?

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

それでも、まだまったく「感じる」わけではありません。 :-/

関連質問: Pythonでリストを均等なサイズのチャンクに分割するにはどうすればよいですか?

408
Ben Blank

Pythonの recipes セクションから変更 itertools docs:

from itertools import Zip_longest

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


例を簡潔にするための擬似コード。

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

注:Python 2では、izip_longestの代わりにZip_longestを使用します。

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

シンプル。簡単です。速い。任意のシーケンスで動作します:

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

私はのファンです

chunk_size= 4
for i in range(0, len(ints), chunk_size):
    chunk = ints[i:i+chunk_size]
    # process chunk of size <= chunk_size
109
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)

別の方法:

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

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

セットとジェネレーターでも機能するソリューションが必要でした。非常に短くてきれいなものは思いつきませんでしたが、少なくともかなり読みやすいです。

def chunker(seq, size):
    res = []
    for el in seq:
        res.append(el)
        if len(res) == size:
            yield res
            res = []
    if res:
        yield res

リスト:

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

セット:

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

ジェネレータ:

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

他の提案と似ていますが、まったく同じというわけではありませんが、シンプルで読みやすいので、このようにするのが好きです。

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)

この方法では、最後の部分的なチャンクは取得されません。最後のチャンクとして(9, None, None, None)を取得する場合は、itertoolsからizip_longestを使用します。

8
kriss

この問題の理想的な解決策は、イテレータ(シーケンスだけでなく)で機能します。また、高速でなければなりません。

これは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)

Macブックエアでipythonの%timeitを使用すると、ループごとに47.5 usを取得します。

ただし、結果が同じサイズのグループになるようにパディングされるため、これは実際には機能しません。パディングなしのソリューションは、もう少し複雑です。最も素朴な解決策は次のとおりです。

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

シンプルだがかなり遅い:ループあたり693 us

私が思いつく最良の解決策は、内部ループにisliceを使用します。

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

同じデータセットで、ループごとに305 usを取得します。

それよりも速く純粋なソリューションを取得できない場合、次のソリューションに重要な警告を提供します。入力データにfilldataのインスタンスが含まれている場合、間違った答えを得る可能性があります。

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

私は本当にこの答えが好きではありませんが、かなり速いです。ループあたり124 us

7
rhettg

まだ誰も言及していないので、ここにZip()ソリューションがあります:

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

シーケンスの長さが常にチャンクサイズで割り切れる場合、またはそうでない場合は後続のチャンクを気にしない場合にのみ機能します。

例:

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

または、 itertools.izip を使用して、リストではなくイテレーターを返します。

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

パディングは @ΤΖΩΤΖΙΟΥの答え を使用して修正できます。

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

Zip()の代わりにmap()を使用すると、J.F。Sebastianの答えのパディングの問題が修正されます。

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

例:

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

外部パッケージの使用を気にしない場合は、 iteration_utilities.grouper from iteration_utilties を使用できます。 1。 (シーケンスだけでなく)すべての反復可能オブジェクトをサポートします。

from iteration_utilities import grouper
seq = list(range(20))
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, 17, 18, 19)

長さがグループサイズの倍数ではない場合、最後のグループの埋め込み(不完全な最後のグループ)または切り捨て(不完全な最後のグループの破棄)もサポートします。

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 免責事項:私はそのパッケージの著者です。

4
MSeifert

小さな機能や物を使うことは本当に魅力的ではありません。私はスライスを使用することを好みます:

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

リストが大きい場合、これを行うための最もパフォーマンスの高い方法は、ジェネレーターを使用することです。

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

NumPyを使用すると簡単です。

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

出力:

1 2
3 4
5 6
7 8
2
endolith

別のアプローチは、iterの2つの引数形式を使用することです。

from itertools import islice

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

これはパディングを使用するように簡単に調整できます(これは 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)

これらはオプションのパディングのために組み合わせることができます:

_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

私が何かを見逃さない限り、ジェネレータ式を使用した次の簡単な解決策は言及されていません。 チャンクのサイズと数の両方が既知である(これがよくあるケースです)、およびパディングが不要であると想定しています:

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

ジェネレーターをサポートするインポートのないチャンカーは次のとおりです。

def chunks(seq, size):
    it = iter(seq)
    while True:
        ret = Tuple(next(it) for _ in range(size))
        if len(ret) == size:
            yield ret
        else:
            raise StopIteration()

使用例:

>>> 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(next(it))
            except StopIteration:
                yield chunk
                raise StopIteration
        yield chunk

if __== '__main__':
    import doctest

    doctest.testmod()
1
ksindi

J.F. Sebastianによる解決策について here

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

それは賢いですが、1つの欠点があります-常にタプルを返します。代わりに文字列を取得する方法は?
もちろん''.join(chunker(...))を書くこともできますが、一時的なタプルはとにかく構築されます。

次のように、独自のZipを記述することで、一時的なタプルを取り除くことができます。

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

それから

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

使用例:

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

私は自分のチャンクをパディングしたくないので、その要件は不可欠です。反復可能なものに取り組む能力も必要条件だと思います。そのため、受け入れられた答え https://stackoverflow.com/a/434411/1074659 を拡張することにしました。

パディングされた値を比較およびフィルタリングする必要があるため、パディングが不要な場合、このアプローチではパフォーマンスがわずかに低下します。ただし、大きなチャンクサイズの場合、このユーティリティは非常に高性能です。

#!/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

2番目の方法では、次の方法で4つの次のグループに進みます。

ints = ints[4:]

ただし、パフォーマンスの測定は行っていないため、どちらが効率的かはわかりません。

そうは言っても、通常は最初の方法を選択します。それはきれいではありませんが、それは多くの場合、外の世界とのインターフェースの結果です。

1
Greg Hewgill

funcy ライブラリの partition または chunks functionを使用できます:

from funcy import partition

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

これらの関数には、イテレータバージョンipartitionおよびichunksもあります。この場合、より効率的です。

それらの実装 を覗くこともできます。

1
Suor

私はこのアプローチが好きです。シンプルで魔法のようではなく、すべての反復可能なタイプをサポートし、インポートを必要としません。

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

さらに別の答え、その利点は次のとおりです。

1)わかりやすい
2)シーケンスだけでなく、反復可能なもので動作します(上記の回答の一部は、ファイルハンドルで停止します)
3)チャンクを一度にメモリにロードしません
4)メモリ内の同じイテレータへの参照のチャンク長リストを作成しません
5)リストの最後に塗りつぶし値のパディングなし

そうは言っても、私は時間を計っていないので、より賢い方法のいくつかよりも遅くなるかもしれませんし、ユースケースを考えると利点のいくつかは無関係かもしれません。

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 

更新:
内部ループと外部ループが同じイテレーターから値をプルしているという事実によるいくつかの欠点:
1)continueは、外側のループで期待どおりに動作しません-チャンクをスキップするのではなく、次の項目に進むだけです。ただし、外側のループでテストするものがないため、これは問題のようには見えません。
2)内部ループでブレークが期待どおりに機能しない-反復子の次の項目で制御が再び内部ループで終了します。チャンク全体をスキップするには、内部反復子(上記のii)をTupleでラップします。 for c in Tuple(ii)、またはフラグを設定してイテレータを使い果たします。

1
elhefe

リストimport itertoolsへのすべての変換を回避するには:

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

生産物:

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

groupbyをチェックしましたが、リストに変換したりlenを使用したりしないので、実際に使用されるまで各値の解決を遅らせると思います。残念ながら、(現時点で)利用可能な回答のどれもこのバリエーションを提供していないようでした。

明らかに、各項目を順番に処理する必要がある場合、gのforループをネストします。

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

これに対する私の特定の関心は、最大1000のバッチで変更をGmail APIに送信するためにジェネレーターを使用する必要があることです。

    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

かなりPythonicです(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
0
Andrey Cizov

サイズ4のチャンクでリストxを反復処理する1行のアドホックソリューション-

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

最初に、16進数を含む文字列を解析するために、文字列を部分文字列に分割するように設計しました。
今日、私はそれを複雑ではあるがシンプルなジェネレーターに変えました。

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は、入力データを含むイテレータ/イテレータ/ジェネレータを含む/生成/反復する、
  • sizeは、もちろん、取得したいチャンクのサイズです。

もっと面白い

  • reductorは呼び出し可能オブジェクトであり、チャンクのコンテンツを反復処理するジェネレーターを受け取ります。
    シーケンスまたは文字列を返すことを期待していますが、それを要求しません。

    この引数として、たとえばlistTuplesetfrozenset
    またはその他の手の込んだもの。この関数を渡して、文字列を返します
    iterableが文字列を含む/生成する/繰り返すことを条件とする):

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

    reductorは、例外を発生させてジェネレーターを閉じる場合があることに注意してください。

  • conditionは、reductorが返したものをすべて受け取る呼び出し可能オブジェクトです。
    Trueに評価するものを返すことにより)承認して譲り渡すことにしました。
    またはそれを辞退し、ジェネレータの作業を終了します(他の何かを返すか、例外を発生させます)。

    iterableの要素数がsizeで割り切れない場合、itが使い果たされると、reductorは、sizeよりも少ない要素を生成するジェネレーターを受け取ります。
    これらの要素を呼び出しましょう最後の要素

    この引数として渡す2つの関数を招待しました。

    • lambda x:x-lasts elementsが生成されます。

    • lambda x: len(x)==<size>-lasts elementsは拒否されます。
      sizeと等しい数を使用して<size>を置き換えます

0
GingerPlusPlus

この答えは文字列のリストを分割する、f.ex. 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

使用

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

これを行うためのきれいな方法はないようです。 ここ は、次のような多くのメソッドがあるページです。

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

イテレータをリストから外すことで、リストのスライスをコピーするだけではないことを望んでいます。ジェネレータはスライスでき、自動的にジェネレータとして機能しますが、リストは1000エントリの巨大なチャンクにスライスされるため、効率が低下します。

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]

使用法:

items = list(range(1,1251))

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

リストが同じサイズの場合、それらをZip()を使用して4タプルのリストに結合できます。例えば:

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

Zip()関数が生成するものは次のとおりです。

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

リストが大きく、リストを組み合わせて大きなリストにしたくない場合は、リストではなくイテレーターを生成するitertools.izip()を使用します。

from itertools import izip

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

一時的なリストを作成せずに、反復可能の反復可能を取得するためにitertools.groupbyを機能させるのは簡単です:

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

ネストされたラムダによって先送りされないでください。外側のラムダは、count()ジェネレーターと定数100を内側のラムダのスコープに入れるために1回だけ実行されます。

これを使用して行のチャンクをmysqlに送信します。

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

リスト内包表記を使用しない理由

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