【问题标题】:Correct way to iterate twice over a list?在列表上迭代两次的正确方法?
【发布时间】:2013-04-13 01:31:01
【问题描述】:

在容器上执行多次迭代的正确方法是什么?来自python文档:

Iterator - 一个容器对象(例如一个列表)产生一个新的 每次将迭代器传递给 iter() 函数或在 for 循环。用迭代器尝试这个只会返回相同的 上一次迭代过程中使用的迭代器对象已用尽,使得 它看起来像一个空容器。

协议的意图是一旦迭代器的 next() 方法 引发 StopIteration,它将在后续调用中继续这样做。 不遵守此属性的实现被视为已损坏。 (此约束是在 Python 2.3 中添加的;在 Python 2.2 中,各种 迭代器根据此规则被破坏。)

如果我有这个代码:

slist = [1,2,3,4]
rlist = reversed(slist)
list(rlist)
#[4,3,2,1]
tuple(rlist)
#()

迭代“rlist”两次最简单、最正确的方法是什么?

【问题讨论】:

  • 请注意,您不会对列表进行两次迭代——这很容易。您实际上是在对 <type 'listreverseiterator'> 进行两次迭代。

标签: python


【解决方案1】:
rlist = list(reversed(slist))

然后根据需要多次迭代。这个技巧更普遍适用;每当您需要多次迭代迭代器时,将其转换为列表。这是一个代码 sn-p,我一直为此目的将其复制粘贴到不同的项目中:

def tosequence(it):
    """Turn iterable into a sequence, avoiding a copy if possible."""
    if not isinstance(it, collections.Sequence):
        it = list(it)
    return it

Sequence 是列表、元组和许多自定义列表类对象的抽象类型。)

【讨论】:

  • 为什么要麻烦测试?如果it 已经是一个列表,我希望it = list(it) 没有成本。不是这样吗?
【解决方案2】:

我不会将列表存储两次,如果你不能将它组合起来迭代一次,那么我会

slist = [1,2,3,4]
for element in reversed(slist):
    print element  # do first iteration stuff
for element in reversed(slist):
    print element  # do second iteration stuff

只需将 reversed() 视为在 slist 上设置反向迭代器。反面便宜。话虽如此,如果您只需要反转它,我会反转它并像这样存储它。

【讨论】:

  • +1 - 调用 reversed(slist) 只会创建一个新的迭代器对象,这比 list(reversed(slist)) 创建整个列表的副本要便宜得多。
【解决方案3】:

对容器执行多次迭代的正确方法是什么?

只需连续执行两次即可。没问题。

迭代“rlist”两次最简单、最正确的方法是什么?

看,不适合你的原因是rlist 不是“容器”。

注意方法

list(slist) # another copy of the list
tuple(slist) # still works!

因此,简单的解决方案是确保在需要多次迭代时拥有一个实际的项目容器:

rlist = list(reversed(slist)) # we store the result of the first iteration
# and then that result can be iterated over multiple times.

如果您真的不能存储这些物品,请尝试itertools.tee。但请注意,如果您需要在开始下一个完整迭代之前完成一个完整的迭代,您将不会真正避免存储这些项目。在一般情况下,在这些限制下,存储确实是不可避免的。

【讨论】:

    【解决方案4】:

    您为什么不简单地原地反转原始列表 (slist.reverse()),然后根据需要对其进行多次迭代,最后再次反转它以再次获得原始列表?

    如果这对您不起作用,以相反顺序迭代列表的最佳解决方案是每次需要迭代时创建一个新的反向迭代器

    for _ in xrange(as_many_times_as_i_wish_to_iterate_this_list_in_reverse_order):
        for x in reversed(slist):
            do_stuff(x)
    

    【讨论】:

    • //,这里为什么要用_作为变量名呢?这是某种约定吗?
    • 我(我也见过其他人这样做)将一次性值分配给下划线变量。这样,当我阅读代码时,我会立即知道该值不相关。另一方面,gettext 库使用 _() 函数...所以我猜在某些情况下,这对于一次性变量来说是个坏名字。
    猜你喜欢
    • 2012-07-06
    • 2011-10-08
    • 2014-05-18
    • 2021-12-20
    • 2019-01-26
    • 1970-01-01
    • 1970-01-01
    • 2015-04-22
    • 2011-02-06
    相关资源
    最近更新 更多