【问题标题】:Python - how to use few times the same next iteration?Python - 如何使用几次相同的下一次迭代?
【发布时间】:2017-11-07 15:52:48
【问题描述】:

我想搜索一个列表:

[0, 0, 1, 0, 1, 1, 1, 0, 1, 1] 

并替换/编辑不同于前一个项目和下一个项目的项目。对于 xxample:我想删除/编辑上面列表中索引 2 处的 1。

看看我下面的代码,请继续阅读我的代码下面的核心问题:

!更新:结果应该是:[0, 0, 0, 0, 1, 1, 1, 1, 1, 1]

x = [0, 0, 1, 0, 1, 1, 1, 0, 1, 1]
print(x)
hiter = iter(x)
next(hiter)
prev = None

for i in x:
    try:
        print('prev %s - CURRENT %s - next %s' % (prev, i, next(hiter)))
        prev = i

        #if i != prev and i != next(hiter):
        #   x[i] = prev 

    except StopIteration:
        break

print(x)

我们知道上一项、下一项和当前项。

但每次我使用:

如果 i != prev 和 i != next(hiter)...

next(hiter) 破坏秩序。换句话说,如果我在循环中使用next(hiter) 超过 1 次,Python 会将下一项读取为 double,因为我在循环中使用了两次 next(hiter)。

我也尝试过声明单独的变量,例如y = next(hiter) - 但它仍然没有工作(显然不会工作,但我还是不顾一切地检查它xD)。

我没有任何线索,另外hiter.__next__()和next(hiter)做的一样。

【问题讨论】:

  • 为什么不迭代索引而不是对象呢?而不是for i in x,使用for i in range(len(x)) 进行迭代,并使用x[i] 访问元素。您将能够访问x[i-1] 和x[i+1],而无需像使用next 那样使用它们。
  • 你能包括“预期输出”吗?索引 3 和 7 的零点呢?
  • 除非我误解了这似乎是一种复杂的方法来解决看似简单的问题,请澄清您的问题和输出
  • 此外,next(x) 执行自身 x.__next__()。
  • 如果你迭代它而不是索引,你将无法修改原始列表。

标签: python list loops iterator next


【解决方案1】:

你自己把这件事弄得太复杂了。相反,只需在循环中多次阅读x:

for idx in range(1, len(x)-1): # Consider using enumerate, it's a great idea
    curr = x[idx]
    prev = x[idx - 1]
    nxt = x[idx + 1]
    if (curr != prev) and (curr != nxt):
        print('prev %s - CURRENT %s - next %s' % (prev, curr, nxt))

【讨论】:

  • 您可以缓存当前和下一个项目的值,而不是从x 访问它们。除此之外,这是一个合理的解决方案。
  • 如果您认为枚举更好,请展示如何。虽然 我不是 Dvoter,但我相信这是因为您选择提供另一种解决方案而没有任何解释,而无视 OP 所做的工作。这通常被看不起。
  • 另外,OP 需要替换坏元素。我仍然赞成
  • 坦率地说,我希望我的代码是不言而喻的。我同意 enumerate 会更干净(尽管我不同意缓存会更干净,即使我确实意识到它会是更快的代码)。不过,我认为这不是枚举用例的正确论坛。
  • @acdr,我一开始不明白 OP 问题,所以我认为你的解决方案是错误的,对不起,我的错误,我做了一点改变(在评论中),所以我可以投票
【解决方案2】:

有一个itertools.tee 函数允许“克隆”迭代器。

iter1, iter2 = itertools.tee(iter(<iterable>))

您的案例似乎太琐碎了-除非它只是示例,否则请使用它

编辑 那样的话

for index, val in enumerate(x[1:-1], 1)
    if val != x[index-1] and val != x[index+1]:
        x[index] = x[index-1]

【讨论】:

  • 这将如何让 OP 真正解决编辑列表中项目的初始问题?
【解决方案3】:

您可以使用生成器来保留前一个项目并向前看一个项目:

def gen(x):
    x = iter(x)
    # Get the first item and simply yield it
    first = next(x)
    yield first

    # create a list containing the previous element, the current element and the next element
    # and iterate over your input.
    three = [None, first, next(x)]
    for item in x:
        # Update the list of elements: Remove the previous previous item and
        # add the new next item.
        three = three[1:] + [item]
        prev, cur, nxt = three

        if cur != prev and cur != nxt:
            three[1] = prev  # replace the current item with the previous item
            yield prev

        else:
            yield cur

    # Simply yield the last item
    yield three[-1]


>>> list(gen([0, 0, 1, 0, 1, 1, 1, 0, 1, 1]))
[0, 0, 0, 0, 1, 1, 1, 1, 1, 1]

在这种方法中,我只是返回第一个和最后一个项目而不进行检查,因为只有下一个或上一个项目而不是两者。如果你愿意,你也可以在那里放一些支票。

正如@MadPhysicist 指出的那样,根本不需要列表,您可以简单地为previous、current 和next 项目使用一个变量:

def gen(x):
    x = iter(x)
    # Get the first item and simply yield it
    first = next(x)
    yield first

    cur, nxt = first, next(x)  # Initial current and next item
    for item in x:
        prev, cur, nxt = cur, nxt, item  # Update the previous, current and next item

        if cur != prev and cur != nxt:
            cur = prev
            yield prev

        else:
            yield cur

    # Simply yield the last item
    yield nxt

注意:这两种方法都将创建一个新列表,并且不会修改原始列表。

【讨论】:

  • 最佳答案。您可能完全不需要three,而只需使用prev、cur、nxt。更新将是prev, cur, nxt = cur, nxt, item。
【解决方案4】:

您可能希望通过索引访问列表元素。在您的循环中,您可以通过添加或减去当前索引来访问上一个和下一个项目。

请记住,在列表中,您可以使用 hiter[0]、hiter[1]、... 访问元素,并且在循环中为:

for i in range(len(hiter)-1):
    print("The item is %s" % hiter[i])

因此您可以访问上一个和下一个,只需要处理边缘情况(以防止索引超出范围)。一种方法是:

for i in range(len(hiter)):
    if 0 < i < (len(hiter) - 1):
        print("The items are %s, %s, %s" % (hiter[i-1], hiter[i], hiter[i+1]))
    elif i == 0:
        print("The items are %s, %s" % (hiter[i], hiter[i+1]))
    elif i == (len(hiter) - 1):
        print("The items are %s, %s" % (hiter[i-1], hiter[i]))

以同样的方式,您可以使用相同的索引方法更改可变列表中的值。

【讨论】:

  • 如果像列表一样使用迭代器,为什么还要使用迭代器?只需按原样使用x。
  • 我试图弄清楚发生了什么......我敢肯定有很多方法可以给这只猫剥皮,但我已经尝试为这个:)
  • 对我来说听起来像是不必要的复杂性。
【解决方案5】:

!更新 2: 感谢大家的贡献。这真的很有帮助,我今天学到了很多。这就是我的意思(对不起@MSeifert,但我必须按照自己的方式去做,我知道生成器速度更快,而且它们不会消耗内存)。
解决方案:

x = [0, 0, 1, 0, 1, 1, 1, 0, 1, 1]
print(x)
for i in range(1, len(x)-1):
    current = x[i]
    nxt = x[i+1]
    prev = x[i-1]

    if current != prev and current != nxt:
        print('prev: %s - CURRENT: %s - next: %s [ X ]' % (prev, current, nxt))
        x[i] = x[i-1]
    else:
        print('prev: %s - CURRENT: %s - next: %s' % (prev, current, nxt))

print(x)

【讨论】:

  • 范围应该从 1 开始,而不是 0。
  • 那么您可能应该接受@acdr's answer(请参阅"How does accepting an answer work?")。这似乎是对您帮助最大的答案(方法似乎大致相同)。您还可以对所有您认为有帮助的答案进行投票。 :) 仅当您的方法与现有答案显着不同时,才应自行回答问题。 :)
  • 完成 :) 抱歉,我是新来的,在这个很棒的论坛上有点迷失。
  • @Mad Physicist 确实,因为我们从第二个索引开始,所以它可以正确读取“上一个”。谢谢。
猜你喜欢
  • 2018-06-10
  • 2014-06-30
  • 2021-10-12
  • 2018-10-27
  • 1970-01-01
  • 2021-10-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多