【问题标题】:How to reset a loop that iterates over a set?如何重置迭代集合的循环?
【发布时间】:2019-07-19 02:01:28
【问题描述】:

如何重置循环遍历集合?迭代列表的常见答案是重置您用于访问列表的索引,但是集合不支持索引。

重点是能够迭代大量对象,对每个元素执行一些操作,直到结果与我需要的结果匹配。我正在寻找的功能是reset 循环的能力。这意味着从一开始就重新开始迭代,以确保我无论出于何种原因再次访问每个元素。

如何重置以下循环?

for element in some_set:
   print element
   if element + offset == needed_result:
      # reset

我正在使用 python 2.7 来解决这个特定问题,但我也欢迎使用 python 3 解决方案。

【问题讨论】:

  • "重置您正在使用的索引" - 这在 for 循环中也不起作用。更广泛的背景是什么,您要解决的问题是什么?
  • 你说的reset是什么意思?你从循环中创建break 并再次开始迭代,但为什么呢?你知道我希望集合是无序的
  • reset 是什么意思?集合并不是“耗尽”的,它总是包含相同的元素,它是不可变的 - 与列表不同,它也是无序的。
  • @jonrsharpe 更广泛的背景就是这样。我正在遍历一个无序的大列表,对于每个元素,我必须散列值并将其与某个值进行比较,直到找到与散列匹配的某个值,但这无关紧要。我希望能够重置此迭代以在给定条件下重新开始。
  • @Chris_Rands 如果我正在迭代一个集合(意味着将我正在访问的元素递增一个),我想重置迭代并在第一个元素处开始完全相同的循环,以确保我可以访问每个值一次。

标签: python python-3.x python-2.7 loops set


【解决方案1】:

一种方法是使用iterators。您可以通过简单地在您的集合上调用iter() 来定义一个迭代器,并在每次迭代时调用它的next 方法。当满足条件时,您可以简单地从集合中再次创建迭代器对象并重复该过程:

s = {1,2,3,4,5}
s_ = iter(s)
# Just a counter to avoid endless loop
cont = 0
while cont < 10:
    try:
        i = next(s_)
    except StopIteration:
        break
    # Some condition
    if flag == True: 
        # Reset the iterator when the condition is met
        s_ = iter(s) 
        continue
    cont += 1

【讨论】:

  • 支持无限循环 - 很酷....你知道cont 是一个正在发生的NameError,即使没有 - 它永远不会超过 1(如果 2 是第二个值迭代)..仍然是一个无限循环;)
  • 嗯,没有关于什么条件会结束循环的信息。添加了一个计数器,因此更清楚它应该在某些条件下中断......但没有更多信息我只是在这里猜测@PatrickArtner
  • 可能想要将 next 包装在 except StopIteration: break 中。
  • 迭代器正是解决我问题的方法。这个问题不关心 what 重置条件是 - 只是会有一个。问题是如何在特定数据结构的循环上执行重置。
【解决方案2】:

我只是将集合转换为列表并使用 while 循环:

sett = {'a','b','c','d','e','f','g','h'}
lisst = list(set)

position = 0
while (position <= 8):
   element = lisst[position]
   print element
   if element + offset == needed_result:
        position = 0
   else:
        position += 1

【讨论】:

  • 集合不支持索引
  • 我意识到你发表评论后需要将其转换为列表,请参阅编辑
【解决方案3】:

这是一个巧妙的技巧,它采用任何类型的可迭代(包括集合),并返回ReIterable 类(我们的“可重置可迭代”的简称)的实例。

然后我们可以在 for 循环中使用可重复迭代作为 for r in my_reiterable,就像我们在 for i in my_iterable 中使用原始迭代一样。

for循环内部,只要条件适合重新设置循环,我们只需调用可重复迭代的reset()方法

这是一个使用集合 s 的示例(但它也可以是一个列表或任何其他可迭代对象):

s = {'a', 'b', 'c', 'd', 'e', 'f'}
r = ReIterable(s)
for i in r:
    print ('In for loop,', i)
    if (i == 'c'):
        resp = str(input('Found "c". Do you want to reset?(y/n):'))
        if (resp == 'y'):
            r.reset()

这是输出(注意,第一次提示用户重置时,用户回复了y,导致集合再次迭代。第二次提示用户重置时,用户回复了n,循环继续进行而没有重置):

In for loop, e
In for loop, c
Found "c". Do you want to reset?(y/n):y
In for loop, e
In for loop, c
Found "c". Do you want to reset?(y/n):n
In for loop, a
In for loop, d
In for loop, b
In for loop, f

这是如何工作的?包装类 ReIterable 使用了for 循环和可迭代对象之间的协议。

ReIterable 类如下所示(但您只需要知道如何使用该类,如上所示):

class ReIterable:
    def __init__(self,original):
        self.original = original
        self.iterator = iter(original)
        self.reset_flag = False

    def __iter__(self):
        return self

    def __next__(self):
        if (self.reset_flag):
            print ('In __next__(), reset_flag True')
            self.iterator = iter(self.original)
            self.reset_flag = False
        return next(self.iterator)

    def reset(self):
        self.reset_flag = True

注意:

除了它支持重置操作之外,ReIterable 类本质上将所有迭代工作委托给原始可迭代对象或其迭代器。实际的“重置”涉及丢弃旧的迭代器并获得一个新的迭代器(在@yatu 的回答中也是如此)。

【讨论】:

    猜你喜欢
    • 2018-11-18
    • 1970-01-01
    • 2014-01-11
    • 1970-01-01
    • 2018-03-17
    • 2016-11-19
    • 1970-01-01
    • 2013-01-29
    • 2021-06-30
    相关资源
    最近更新 更多