web-dev-qa-db-ja.com

リストスライスの反復

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

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

_for list_of_x_items in fatherList:
    foo(list_of_x_items)
_

_list_of_x_items_を適切に定義する方法、またはpython 2.5を使用してこれを行う他の方法はありますか?


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

FatherListは、ファイルから取得しているマルチレベルのnumpy.arrayです。関数は系列の平均を見つける必要があります(ユーザーは系列の長さを指定します)平均化には、mean()関数を使用しています。質問の拡張について:

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

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


関連:

28
Rince

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

質問の更新:追加のアイテムを格納し、次の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
8
jfs

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

_list_of_slices = Zip(*(iter(the_list),) * slice_size)
_

例えば

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

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

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

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


OK、それがどのように機能するかを説明します。説明するのは難しいですが、私は最善を尽くします。

最初の少し背景:

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

そして iterator オブジェクトは次のように一度消費することができます:

_>>> 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_->は、_listイテレータへのN参照を生成します。

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

それがそれを説明することを願っています。わかりやすい解決策を選択することをお勧めします。私はそれが好きなので、このトリックについて言及したくなりました。

62
Nadia Alramli

反復可能なものを消費できるようにしたい場合は、次の関数を使用できます。

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)
21
Ants Aasma

次のような意味ですか:

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

ジェネレーターを使用する:

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)

sliceIteratorは、シーケンスsliceLen上に幅lstの「スライディングウィンドウ」を実装します。つまり、重複するスライスを生成します:[1,2,3]、[2,3,4 ]、[3,4,5]、...それがOPの意図であるかどうかはわかりませんが。

7
ThomasH

よくわかりませんが、いわゆる移動平均をやりたいようです。 numpyは、このための機能(畳み込み関数)を提供します。

 >>> x = numpy.array(range(20))
 >>> x 
 array([0、1、2、3、4、5、6、 7、8、9、10、11、12、13、14、15、16、
 17、18、19])
 >>> n = 2#移動平均ウィンドウ
 >>> numpy.convolve(numpy.ones(n)/ n、x)[n-1:-n + 1] 
 array([0.5、1.5、2.5、3.5、4.5、5.5、 6.5、7.5、8.5、
 9.5、10.5、11.5、12.5、13.5、14.5、15.5、16.5、17.5、18.5])

良い点は、さまざまな重み付けスキームにうまく対応できることです(numpy.ones(n) / nを別のものに変更するだけです)。

完全な資料はここにあります: http://www.scipy.org/Cookbook/SignalSmooth

5
LeMiz

@Ants Aasmaの回答を拡張:Python 3.7 StopIteration例外の処理 変更PEP-479による) )。互換性のあるバージョンは次のようになります。

from itertools import chain, islice

def ichunked(seq, chunksize):
    it = iter(seq)
    while True:
        try:
            yield chain([next(it)], islice(it, chunksize - 1))
        except StopIteration:
            return
2
Tim-Erwin

パディングなしでチャンク分割不可能なサイズを処理するナディアの答えの静脈にあるほぼ1つのライナー(itertoolsインポート後)の場合:

_>>> 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をインポートしている場合は、ピンチに役立ちます。

2
Dologan

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

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)
2
Ned Batchelder