web-dev-qa-db-ja.com

Pythonでジェネレータまたはリストから最初のN項目を取り出す方法

linq 私は

var top5 = array.Take(5);

Pythonでこれを行うには?

251
Jader Dias

リストをスライスする

top5 = array[:5]
  • リストをスライスするには、簡単な構文があります:array[start:stop:step]
  • 任意のパラメータを省略できます。これらはすべて有効です:array[start:]array[:stop]array[::step]

ジェネレータをスライスする

 import itertools
 top5 = itertools.islice(my_list, 5) # grab the first five elements
  • Pythonではジェネレータを直接スライスすることはできません。 itertools.islice() は、構文itertools.islice(generator, start, stop, step)を使って、オブジェクトを新しいスライスジェネレータにラップします。

  • ジェネレータをスライスすると、部分的に使い果たされます。ジェネレータ全体を無傷のままにしておきたい場合は、おそらく以下のように最初にそれをタプルまたはリストに変換してください:result = Tuple(generator)

405
lunixbochs
import itertools

top5 = itertools.islice(array, 5)
104
Jader Dias

私の好みでは、 'Zip()'と 'xrange(n)'(またはPython 3では 'range(n)')を組み合わせることも非常に簡潔です。これはジェネレータでも同様に機能し、一般的な。

# Option #1: taking the first n elements as a list
[x for _, x in Zip(xrange(n), generator)]

# Option #2, using 'next()' and taking care for 'StopIteration'
[next(generator) for _ in xrange(n)]

# Option #3: taking the first n elements as a new generator
(x for _, x in Zip(xrange(n), generator))

# Option #4: yielding them by simply preparing a function
# (but take care for 'StopIteration')
def top_n(n, generator):
    for _ in xrange(n): yield next(generator)
30
Shaikovsky

@ Shaikovskyの答えは優れています(…そしてこの答えを投稿してから大幅に編集されました)が、いくつかポイントを明確にしたいと思いました。

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

これは最も単純なアプローチですが、ジェネレータが時期尚早に使い果たされるとStopIterationをスローします。


一方、次のアプローチでは最大でn項目が返されますが、これはほとんどの状況で間違いなく望ましい方法です。

リスト:[x for _, x in Zip(range(n), records)]

ジェネレータ:(x for _, x in Zip(range(n), records))

19

これを行う方法の答えは見つけることができます こちら

>>> generator = (i for i in xrange(10))
>>> list(next(generator) for _ in range(4))
[0, 1, 2, 3]
>>> list(next(generator) for _ in range(4))
[4, 5, 6, 7]
>>> list(next(generator) for _ in range(4))
[8, 9]

最後の呼び出しは、残りが2つのみである場合に、次の4つを要求することに注意してください。 []の代わりにlist()を使用すると、next()によってスローされるStopIteration例外で終了するように理解できます。

12
ebergerson

最初の N個のアイテム、またはN 最大 N個のアイテムという意味ですか?

あなたが最初が欲しいならば:

top5 = sequence[:5]

あなたのシーケンスが降順でソートされていると仮定すれば、これは最大N個のアイテムに対しても働きます。 (あなたのLINQの例でもこれを仮定しているようです。)

最大のものが欲しくて、それがソートされていない場合、最も明白な解決策はそれを最初にソートすることです:

l = list(sequence)
l.sort(reverse=True)
top5 = l[:5]

より高性能な解決策としては、min-heapを使用してください(Thijsに感謝)。

import heapq
top5 = heapq.nlargest(5, sequence)
5
Thomas

itertoolsを使用すると、別のジェネレータオブジェクトを取得できるため、ほとんどの場合、最初のN個の要素を取るための別の手順が必要になります(N)。 generatorから要素を使えるようにするには、少なくとも2つの単純な解決策(パフォーマンスの面では少し効率が悪いが非常に便利)があります。

リスト内包表記を使う:

first_N_element=[generator.next() for i in range(N)]

さもないと:

first_N_element=list(generator)[:N]

ここでNはあなたがとりたい要素の数です(例えば最初の5つの要素に対してN = 5)。

3
G M