Как взять первые 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)
на мой вкус, это также очень лаконично, чтобы объединить "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 для первые пять элементов).