Как взять первые N элементов из генератора или списка в Python? [дубликат]

этот вопрос уже есть ответ здесь:

  • как получить N следующих значений генератора в списке (python) 4 ответы

С в LINQ Я

var top5 = array.Take(5);

Как это сделать с Python?

8 ответов


нарезка списка

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)


import itertools

top5 = itertools.islice(array, 5)

на мой вкус, это также очень лаконично, чтобы объединить "zip ()" с "xrange(n)" (или "range(n)" в Python3), который хорошо работает на генераторах, а также и кажется более гибким для изменений в целом.

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

@Shaikovsky's ответ отличный, но я хотел бы уточнить несколько моментов.

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

Это самый простой подход, но бросает StopIteration если генератор преждевременно исчерпан.


С другой стороны, следующие подходы возврата до n элементы, которые, возможно, предпочтительнее в большинстве случаев:

список: [x for _, x in zip(range(n), records)]

генератор: (x for _, x in zip(range(n), records))


ответ, как это сделать можно найти здесь

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

обратите внимание, что последний вызов запрашивает следующие 4, когда остаются только 2. Использование list() вместо [] что получает понимание прекращенным с StopIteration исключение, которое выбрасывается next().


вы имеете в виду первый n элементов, или N большой предметы?

Если вы хотите первым:

top5 = sequence[:5]

Это также работает для самых больших n элементов, предполагая, что ваша последовательность отсортирована в порядке убывания. (Ваш пример LINQ, похоже, также предполагает это.)

Если вы хотите самый большой, и он не сортируется, самое очевидное решение-сначала отсортировать его:

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

для более эффективного решения используйте минимальную кучу (спасибо Тайс):

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

С itertools вы получите другой объект генератора, поэтому в большинстве случаев вам понадобится еще один шаг, чтобы взять первые N элементов (N). Есть, по крайней мере, два более простых решения (немного менее эффективных с точки зрения производительности, но очень удобных), чтобы получить элементы, готовые к использованию из generator:

используя список осмысления:

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

иначе:

first_N_element=list(generator)[:N]

здесь N - количество элементов, которые вы хотите взять (например, N=5 для первые пять элементов).


Это должно работать

top5 = array[:5]