如何获取除最后 n 个可迭代值之外的所有值
Posted
技术标签:
【中文标题】如何获取除最后 n 个可迭代值之外的所有值【英文标题】:How to get all but the last n values of iterable 【发布时间】:2021-02-17 17:15:02 【问题描述】:def drop(iterable, n):
iterator = iter(iterable)
iter_list = []
try:
while True:
it = next(iterator)
if len(iter_list) <= n:
iter_list.append(it)
yield it
except StopIteration:
pass
我想从可迭代对象中生成除最后 n 个值之外的所有值。现在,我拥有它,以便它最多产生 n 个值。我该怎么做才能让它反其道而行之?如果可以的话,我想保持相同的结构。
我不允许计算迭代产生的值的数量。我也不能在可迭代对象上使用 itertools 或调用 len、index、slice 等。
【问题讨论】:
你能提供一些例子吗? 你是不是建议len(iter_list)
不计算迭代产生的值的数量?
这取决于可迭代对象的长度是否是确定性的,如果可迭代对象的长度未知,则除了将其全部消耗然后丢弃最后 n 项之外别无选择。
这就是 collections.dequeue 的用途!将前 n 个元素读入队列。当用户要求一个新元素时,在末尾添加一个元素并从前面删除一个元素并将其返回给他们。
@khelwood 不,但你至少需要n
空间,我很确定。
【参考方案1】:
这里有 2 个选项,首先是生成整个可迭代对象并删除最后一个 n,然后在 while 循环中,您从头开始返回每个值,或者更巧妙地使用 n 值的缓冲区。只需对您的代码稍作修改即可解决问题
def drop(iterable, n):
iterator = iter(iterable)
iter_list = []
try:
while True:
it = next(iterator)
iter_list.append(it)
if len(iter_list) > n:
element = iter_list.pop(0)
yield element
except StopIteration:
pass
这里每个新元素都附加到 while 循环中,并且在生成前 n 个元素之后运行产生元素的条件。然后产生第一个生成的元素,依此类推,总是生成 n 个元素。当迭代器没有更多可以给出异常并且while循环停止保留最后n个永远不会返回的元素时
【讨论】:
我忘了提及,但我不允许将可迭代的所有值附加到列表中。 使用这种方法,您不会只在新的返回旧的时附加所有的 n 抱歉,我误会了。似乎 iter_list.append(it) 在将其列表长度与 n 进行比较之前将 iterable 的每个值附加到 iter_list 不只是第一个 n,之后它会从列表中删除一个值并添加一个新值。我还可以建议在您的原始代码中,您不需要将值附加到列表中,只需保留一个计数器来比较而不是列表的 len 我该怎么做?【参考方案2】:from collections import deque
def drop(it, n):
queue = deque()
for _ in range(n):
queue.append(next(it))
while True:
# If next(it) throws a StopIteration, we need a little bit more
# code here to indicate this iterable if finished.
queue.append(next(it))
yield queue.popleft()
我可能需要添加几个 try/except StopIteration 以使其完美运行,但这是基本思想。
【讨论】:
这是一个完整的版本:gist.github.com/juanarrivillaga/… 随意填写。 你是说你找不到它?或者你不被允许使用它?只需使用列表 (queue = []
) 并将 queue.popleft()
替换为 queue.pop(0)
。如果列表很长,则从列表中弹出最左边的元素是低效的,但是当您被禁止使用最佳工具时。 . .以上是关于如何获取除最后 n 个可迭代值之外的所有值的主要内容,如果未能解决你的问题,请参考以下文章