【发布时间】:2021-09-13 00:32:19
【问题描述】:
【问题讨论】:
-
对于列表和生成器都提出了这个问题,这令人困惑,这些问题应该是单独的问题
标签: linq python list generator
【问题讨论】:
标签: linq python list generator
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)
【讨论】:
itertools.islice会返回一个生成器。
generator, another_copy = itertools.tee(generator)
@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))
【讨论】:
[next(generator, None) for _ in range(n)] 如果你不介意None
在我看来,将zip() 与xrange(n)(或Python3 中的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)
【讨论】:
您是指前 N 个项目,还是N 个最大 个项目?
如果你想要第一个:
top5 = sequence[:5]
这也适用于最大的 N 个项目,假设您的序列按降序排序。 (您的 LINQ 示例似乎也假设了这一点。)
如果你想要最大的,并且没有排序,最明显的解决方案是先排序:
l = list(sequence)
l.sort(reverse=True)
top5 = l[:5]
要获得更高性能的解决方案,请使用最小堆(感谢 Thijs):
import heapq
top5 = heapq.nlargest(5, sequence)
【讨论】:
import heapq; top5 = heapq.nlargest(5, iterable)
nlargest 接受任何可迭代的,不仅仅是序列。
如何做到这一点的答案可以找到here
>>> 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 异常上终止的理解。
【讨论】:
RuntimeError(尽管该链接绝对值得一读!)
使用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]
【讨论】:
__getitem__()。例如,尝试运行itertools.count()[:5] 或(x for x in range(10))[:5],然后查看错误消息。然而,对于列表来说,答案是惯用的。
import itertools
top5 = itertools.islice(array, 5)
【讨论】:
def take(n, iterable): return list(islice(iterable, n))