35

リストのスライスを反復処理するアルゴリズムが必要です。スライスのサイズは関数の外で設定され、異なる場合があります。

私の考えでは、それは次のようなものです:

for list_of_x_items in fatherList:
    foo(list_of_x_items)

Python 2.5を使用してこれを適切に定義する方法list_of_x_itemsまたは他の方法はありますか?


edit1: 明確化「パーティショニング」と「スライディング ウィンドウ」の両方の用語が私のタスクに当てはまるように聞こえますが、私は専門家ではありません。したがって、問題をもう少し詳しく説明し、質問に追加します。

FatherList は、ファイルから取得しているマルチレベルの numpy.array です。関数はシリーズの平均を見つける必要があります(ユーザーはシリーズの長さを提供します)平均化のために私はmean()関数を使用しています。質問の展開について:

edit2:追加のアイテムを保存し、次のfatherListが関数に供給されたときにそれらを使用するために提供した関数を変更する方法は?

たとえば、リストの長さが 10 で、チャンクのサイズが 3 の場合、リストの 10 番目のメンバーが格納され、次のリストの先頭に追加されます。


関連している:

4

10 に答える 10

70

リストをスライスに分割したい場合は、次のトリックを使用できます。

list_of_slices = zip(*(iter(the_list),) * slice_size)

例えば

>>> zip(*(iter(range(10)),) * 3)
[(0, 1, 2), (3, 4, 5), (6, 7, 8)]

アイテムの数がスライス サイズで割り切れず、リストを None で埋めたい場合は、次のようにします。

>>> map(None, *(iter(range(10)),) * 3)
[(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, None, None)]

それは汚い小さなトリックです


わかりました、それがどのように機能するかを説明します。説明するのは難しいですが、頑張ってみます。

最初に少し背景を説明します:

Python では、次のようにリストに数値を掛けることができます。

[1, 2, 3] * 3 -> [1, 2, 3, 1, 2, 3, 1, 2, 3]
([1, 2, 3],) * 3 -> ([1, 2, 3], [1, 2, 3], [1, 2, 3])

そして、イテレータオブジェクトは次のように 1 回消費できます。

>>> l=iter([1, 2, 3])
>>> l.next()
1
>>> l.next()
2
>>> l.next()
3

zip関数は、タプルのリストを返します。ここで、i 番目のタプルには、各引数シーケンスまたはイテラブルの i 番目の要素が含まれます。例えば:

zip([1, 2, 3], [20, 30, 40]) -> [(1, 20), (2, 30), (3, 40)]
zip(*[(1, 20), (2, 30), (3, 40)]) -> [[1, 2, 3], [20, 30, 40]]

zip の前の * は、引数をアンパックするために使用されます。詳細については、こちらをご覧ください。そう

zip(*[(1, 20), (2, 30), (3, 40)])

実際には同等です

zip((1, 20), (2, 30), (3, 40))

しかし、可変数の引数で動作します

トリックに戻ります。

list_of_slices = zip(*(iter(the_list),) * slice_size)

iter(the_list)-> リストをイテレータに変換します

(iter(the_list),) * N-> は the_list イテレータへの N 参照を生成します。

zip(*(iter(the_list),) * N)-> これらのイテレータのリストを zip にフィードします。次に、それらを N サイズのタプルにグループ化します。しかし、実際にはすべての N 個の項目が同じ反復子への参照であるため、結果は元の反復子でのiter(the_list)呼び出しが繰り返されます。next()

それがそれを説明することを願っています。より理解しやすいソリューションを使用することをお勧めします。私はそれが好きなので、このトリックについて言及したかっただけです。

于 2009-08-26T15:35:05.303 に答える
21

イテラブルを消費できるようにしたい場合は、次の関数を使用できます。

from itertools import chain, islice

def ichunked(seq, chunksize):
    """Yields items from an iterator in iterable chunks."""
    it = iter(seq)
    while True:
        yield chain([it.next()], islice(it, chunksize-1))

def chunked(seq, chunksize):
    """Yields items from an iterator in list chunks."""
    for chunk in ichunked(seq, chunksize):
        yield list(chunk)
于 2009-08-26T15:28:54.347 に答える
11

ジェネレーターを使用します。

big_list = [1,2,3,4,5,6,7,8,9]
slice_length = 3
def sliceIterator(lst, sliceLen):
    for i in range(len(lst) - sliceLen + 1):
        yield lst[i:i + sliceLen]

for slice in sliceIterator(big_list, slice_length):
    foo(slice)

sliceIteratorsliceLensquence 上の幅の「スライディング ウィンドウ」を実装しますlst。つまり、重なり合うスライスを生成します: [1,2,3]、[2,3,4]、[3,4,5]、...ただし、OPの意図。

于 2009-08-26T15:13:22.787 に答える
8

質問の最後の部分への回答:

質問の更新:追加のアイテムを保存し、次のfatherListが関数に供給されるときにそれらを使用するために、提供した関数を変更するにはどうすればよいですか?

状態を保存する必要がある場合は、そのためのオブジェクトを使用できます。

class Chunker(object):
    """Split `iterable` on evenly sized chunks.

    Leftovers are remembered and yielded at the next call.
    """
    def __init__(self, chunksize):
        assert chunksize > 0
        self.chunksize = chunksize        
        self.chunk = []

    def __call__(self, iterable):
        """Yield items from `iterable` `self.chunksize` at the time."""
        assert len(self.chunk) < self.chunksize
        for item in iterable:
            self.chunk.append(item)
            if len(self.chunk) == self.chunksize:
                # yield collected full chunk
                yield self.chunk
                self.chunk = [] 

例:

chunker = Chunker(3)
for s in "abcd", "efgh":
    for chunk in chunker(s):
        print ''.join(chunk)

if chunker.chunk: # is there anything left?
    print ''.join(chunker.chunk)

出力:

abc
def
gh
于 2009-08-26T19:02:07.803 に答える
8

次のような意味ですか。

def callonslices(size, fatherList, foo):
  for i in xrange(0, len(fatherList), size):
    foo(fatherList[i:i+size])

これが大まかな機能である場合は、必要に応じて、ジェネレーターで少しドレスアップしてください。

def sliceup(size, fatherList):
  for i in xrange(0, len(fatherList), size):
    yield fatherList[i:i+size]

その後:

def callonslices(size, fatherList, foo):
  for sli in sliceup(size, fatherList):
    foo(sli)
于 2009-08-26T15:12:18.437 に答える
2

あなたの質問はもう少し詳細を使用できますが、どうですか:

def iterate_over_slices(the_list, slice_size):
    for start in range(0, len(the_list)-slice_size):
        slice = the_list[start:start+slice_size]
        foo(slice)
于 2009-08-26T15:13:03.333 に答える
1

itertoolsパディングなしでチャンクで割り切れないサイズを扱うナディアの答えの流れにあるほぼ1つのライナー(インポート後)の場合:

>>> import itertools as itt
>>> chunksize = 5
>>> myseq = range(18)
>>> cnt = itt.count()
>>> print [ tuple(grp) for k,grp in itt.groupby(myseq, key=lambda x: cnt.next()//chunksize%2)]
[(0, 1, 2, 3, 4), (5, 6, 7, 8, 9), (10, 11, 12, 13, 14), (15, 16, 17)]

必要に応じて、かなり醜いitertools.count()を使用して要件を取り除くことができます。enumerate()

[ [e[1] for e in grp] for k,grp in itt.groupby(enumerate(myseq), key=lambda x: x[0]//chunksize%2) ]

(この例でenumerate()は不要ですが、すべてのシーケンスがこのような適切な範囲であるとは限りません)

他のいくつかの回答ほどきちんとしたものではありませんが、特にすでにインポートしている場合は、ピンチで役立ちitertoolsます。

于 2014-05-21T18:07:21.280 に答える