列表的迭代器上的Python循环,该列表的长度在循环过程中发生了更改



假设我想做以下事情:我有一个列表l,在每一步我都想检查l[i]l[i+1]之间的一些条件,如果满足,我会在l[i+1]的基础上更新l[i]并删除l[i+1],然后我会检查l[i]和以前的l[i+2]之间的条件,现在是新的l[i+1]等等。如果在某一步条件不满足,我只是做i+=1

我的实现如下:

i = 0
while i < len(l): 
    if condition(l[i],l[i+1]):
        l[i] = update(l[i+1])
        del l[i+1]
    else:
        i += 1

不幸的是,len(l)只计算一次,当检查while子句时,只有i发生变化,而不是len(l)。因此,在某个时刻,如果我删除了一些元素,我会得到一个索引超出范围的错误。当我在迭代时插入列表的新成员时,会出现类似的问题。

首先,根据您的描述,我认为您想要del l[i+1],而不是del l[i]

在我看来,你的代码确实有效,我认为len(l)每次都在更新,因为我的例子可以在我们希望的时候停止:

l = range(20)
i = 0
while i < len(l):
    print i, len(l), l
    if l[i] % 3 == 0:
        l[i] = -l[i+1]
        del l[i+1]
    else:
        i += 1

然而,如果您的条件在最后一步评估为true,那么您将遇到索引错误,如本例所示:

l = range(20)
i = 0
while i < len(l):
    print i, len(l), l
    if True:
        l[i] = -l[i+1]
        del l[i+1]
    else:
        i += 1

这是因为您检查了i < len(l),然后尝试访问索引i+1。当你到达最后一个元素时,你想做什么?停下来?那么也许你需要这个:

i = 0
while i + 1 < len(l): 
    if condition(l[i],l[i+1]):
        l[i] = update(l[i+1])
        del l[i+1]
    else:
        i += 1

IMHO,有两种方法可以做到这一点:

  • 使用Padraic Cunningham建议的第二个列表:

    i = 0
    l2 = []
    while i < len(l) - 1: 
        if insert_condition_before(l[i]):
            l2.append(for_insert_beore(l[i])) # insert before l[i]
        if condition(l[i],l[i+1]):
            l[i] = update(l[i+1])
            i += 1 # skip l+1
        l2.append(l[i])
        i += 1
        if insert_condition_after(l[i]):
            l2.append(for_insert_after(l[i])) # insert after l[i]
    
  • 使用try-catch来确定阵列的末尾

    i = 0
    try:
        while True: 
            if insert_condition_before(l[i]):
                l.insert(for_insert_before(l[i])) # insert before l[i]
                i += 1
            if condition(l[i],l[i+1]):
                l[i] = update(l[i+1])
                del l[i+1]
            i += 1
            if insert_condition_after(l[i]):
                l.insert(for_insert_after(l[i])) # insert after l[i]
                i += 1 # if you do not want to analyse it again
    except IndexError:
        pass
    

最新更新