web-dev-qa-db-ja.com

リスト内のジェネレーターの次のn個の値を取得する方法(python)

私はWordごとにファイルを読み取るジェネレーターを作成しましたが、それはうまく機能します。

def Word_reader(file):
    for line in open(file):
        for p in line.split():
            yield p

reader = Word_reader('txtfile')
next(reader)

リスト内の次のn個の値を取得する最も簡単な方法は何ですか?

44
Peter Smit

使用する itertools.islice

list(itertools.islice(it, n))

[〜#〜]編集[〜#〜]:_itertools.islice_を使用します。私が最初に提案した以下のパターンは悪い考えです。itの値がn未満になるとクラッシュします。この動作は微妙な問題に依存するため、このようなコードを読んでいる人は、その正確さを理解できない可能性があります。セマンティクス。

もあります

_[next(it) for _ in range(n)]
_

itertoolsに精通していない人にとってはどちらがより明確かもしれません(?)。しかし、イテレータを頻繁に扱う場合、itertoolsはツールセットに追加する価値があります。

next(it)が使い果たされてStopIterationが発生した場合はどうなりますか?

(つまり、itの値がn未満の場合)

数年前に上記の行を書いたとき、おそらくStopIterationにはリスト内包表記をきれいに終了するという巧妙な副作用があると思いました。しかし、いいえ、全体の理解はStopIterationを上向きに渡すとクラッシュします。 (例外がrange(n)イテレータから発生した場合にのみ、正常に終了します。)

これはおそらくあなたが望む振る舞いではありません。

しかし、それはさらに悪化します。以下はリスト内包表記と同等であると想定されています(特にPython 3):

_list(next(it) for _ in range(n))
_

そうではありません。内側の部分はジェネレーター関数の省略形です。 list()は、StopIterationanywhereを発生させたときに完了したことを認識します。
=>このバージョンは、n値がない場合に安全に対処し、より短いリストを返します。 (itertools.islice()のように。)

[実行: 2.7.4 ]

しかし、それも変わるでしょう!ジェネレーター内のコードがStopIterationを発生させると、ジェネレーターがサイレントに終了するという事実は、 PEP 479 で対処される既知の疣贅です。 Python 3.7(または将来のインポートでは3.5)から、ジェネレーターをクリーンに終了する代わりにRuntimeErrorが発生します。つまり、リスト内包表記の動作に似たものになります。 (最近のHEADビルドでテスト済み)

for Word, i in Zip(Word_reader(file), xrange(n)):
    ...
2
dan_waterworth

ジェネレーターの最初のn個の値を取得するには、 more_itertools.take を使用できます。

チャンク内の単語(たとえば、一度に100)を反復処理する場合は、more_itertools.chunked( https://more-itertools.readthedocs.io/en/latest)を使用できます。 /api.html ):

import more_itertools
for words in more_itertools.chunked(reader, n=100):
    # process 100 words
2
JustAC0der

cytoolz.take を使用します。

>>> from cytoolz import take
>>> list(take(2, [10, 20, 30, 40, 50]))
[10, 20]
1
W.P. McNeill