如何获取除最后 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 个可迭代值之外的所有值的主要内容,如果未能解决你的问题,请参考以下文章

如何选择除最后一个子元素之外的元素的所有子元素?

如何获取复选框值?

如何打印除dict中的键之外的所有键的值[重复]

如何从表中选择除外表中的值之外的所有值?

如何在 DotNetNuke 中获取除“管理”选项卡之外的所有选项卡?

如何在下拉列表中获取除隐藏和提交按钮之外的所有表单字段