Python 删除列表项时出现意外的索引器错误

Python 删除列表项时出现意外的索引器错误,python,list,python-2.7,Python,List,Python 2.7,我是Python的初学者。我以前学过其他语言,如C++(初学者)和jQuery。但是我发现python中的循环非常混乱 我想得到一个简单的结果。程序将在单词列表中循环,然后删除与列表中前两个字母匹配的单词和下一个单词: test = ['aac', 'aad', 'aac', 'asd', 'msc'] for i in range(len(test)): if test[i][0:2] == test[i+1][0:2]: test.remove(test[i]) #

我是Python的初学者。我以前学过其他语言,如C++(初学者)和jQuery。但是我发现python中的循环非常混乱

我想得到一个简单的结果。程序将在单词列表中循环,然后删除与列表中前两个字母匹配的单词和下一个单词:

test = ['aac', 'aad', 'aac', 'asd', 'msc']
for i in range(len(test)):
    if test[i][0:2] == test[i+1][0:2]:
        test.remove(test[i])

# This should output only ['aac', 'asd', 'msc']
print test

上述代码应从列表中删除
'aac'
'aad'
。但实际上,这会产生一个
索引器
。此外,我也没能达到预期的效果。您能解释一下吗?

当您从列表中删除项目时,
范围(len(test))
仍然保持相同的值。因此,即使您的
测试
列表只剩下一个项目,循环仍在继续

我有两个解决方案:

  • 将您想要的项目复制到一个新列表中,因此不要删除它:

    test2 = test[i]
    
    别忘了扭转局面

  • 向后循环。像这样:

    n = len(test)
    for i in range(n):
        j = n - i - 1
        if j > 1:
        if test[j][0:2] == test[j-1][0:2]:
            test.remove(test[j])
    
    或者,正如martijn所建议的:

    n = len(test)
    for i in range(n-1, 0, -1):
        if i > 1:
        if test[i][0:2] == test[i-1][0:2]:
            test.remove(test[i])
    
  • 希望有帮助


    p.S对不起,我以前的回答很愚蠢

    当您从列表中删除项目时,
    范围(len(test))
    仍然保持相同的值。因此,即使您的
    测试
    列表只剩下一个项目,循环仍在继续

    我有两个解决方案:

  • 将您想要的项目复制到一个新列表中,因此不要删除它:

    test2 = test[i]
    
    别忘了扭转局面

  • 向后循环。像这样:

    n = len(test)
    for i in range(n):
        j = n - i - 1
        if j > 1:
        if test[j][0:2] == test[j-1][0:2]:
            test.remove(test[j])
    
    或者,正如martijn所建议的:

    n = len(test)
    for i in range(n-1, 0, -1):
        if i > 1:
        if test[i][0:2] == test[i-1][0:2]:
            test.remove(test[i])
    
  • 希望有帮助

    p.S对不起,我之前愚蠢的回答

    ,因为我在范围内(len(test))
    为您提供了一个有效索引为
    test
    的列表。但是,当您不断从循环中的
    test
    中删除项目时,
    test
    的大小会减小,导致一些原来有效的索引变得无效

    你所做的是这样的:

    L = range(len(test))
    for i in L:
      if condition:
        # remove something from test <- the size of test has changed.
                                     # L[-1] is no longer a valid index in test
    
    输出

    In [70]: test = ['aac', 'aad', 'aac', 'asd', 'msc']
    
    In [71]: %paste
    deleteThese = set()
    for i,item in enumerate(test[:-1]):
      if item[0:2] == test[i+1][0:2]:
        deleteThese.add(i)
    test = [item for i,item in enumerate(test) if i not in deleteThese]
    
    ## -- End pasted text --
    
    In [72]: test
    Out[72]: ['aac', 'asd', 'msc']
    
    对于范围内的i(len(test))
    提供了一个包含有效索引的列表
    test
    。但是,当您不断从循环中的
    test
    中删除项目时,
    test
    的大小会减小,导致一些原来有效的索引变得无效

    你所做的是这样的:

    L = range(len(test))
    for i in L:
      if condition:
        # remove something from test <- the size of test has changed.
                                     # L[-1] is no longer a valid index in test
    
    输出

    In [70]: test = ['aac', 'aad', 'aac', 'asd', 'msc']
    
    In [71]: %paste
    deleteThese = set()
    for i,item in enumerate(test[:-1]):
      if item[0:2] == test[i+1][0:2]:
        deleteThese.add(i)
    test = [item for i,item in enumerate(test) if i not in deleteThese]
    
    ## -- End pasted text --
    
    In [72]: test
    Out[72]: ['aac', 'asd', 'msc']
    

    您正在更改列表的长度,同时在一个范围内循环,直到列表的起始长度;从列表中删除一项,则最后一个索引不再有效

    Moveover,因为项目在当前索引处从列表中移除,所以列表的其余索引将移动;在索引
    i+1
    处的内容现在在索引
    i
    处,循环索引不再有用

    最后但并非最不重要的一点是,您正在循环,直到
    test
    的最后一个索引,然后仍然尝试访问
    test[i+1]
    ;即使未从列表中删除元素,该索引也不存在

    您可以使用
    while
    循环来实现您想要做的事情:

    test = ['aac', 'aad', 'aac', 'asd', 'msc']
    i = 0
    while i < len(test) - 1:
        if test[i][:2] == test[i+1][:2]:
            del test[i]
            continue
        i += 1
    
    您可以使用列表理解来避免缩小列表的问题:

    >>> [t for i, t in enumerate(test) if i == len(test) - 1 or t[:2] != test[i + 1][:2]]
    ['aac', 'asd', 'msc']
    

    这两种方法都只需要在输入列表中进行一次循环。

    您正在更改列表的长度,同时循环到列表的起始长度;从列表中删除一项,则最后一个索引不再有效

    Moveover,因为项目在当前索引处从列表中移除,所以列表的其余索引将移动;在索引
    i+1
    处的内容现在在索引
    i
    处,循环索引不再有用

    最后但并非最不重要的一点是,您正在循环,直到
    test
    的最后一个索引,然后仍然尝试访问
    test[i+1]
    ;即使未从列表中删除元素,该索引也不存在

    您可以使用
    while
    循环来实现您想要做的事情:

    test = ['aac', 'aad', 'aac', 'asd', 'msc']
    i = 0
    while i < len(test) - 1:
        if test[i][:2] == test[i+1][:2]:
            del test[i]
            continue
        i += 1
    
    您可以使用列表理解来避免缩小列表的问题:

    >>> [t for i, t in enumerate(test) if i == len(test) - 1 or t[:2] != test[i + 1][:2]]
    ['aac', 'asd', 'msc']
    

    这两种方法都只需要在输入列表中进行一次循环。

    正如其他人所说,当您删除项目时,列表会变短,从而导致索引错误

    与原问题保持一致。如果您希望使用list.remove()删除项目,则可以将找到的项目添加到列表中,然后对其进行迭代,并将其从原始列表中删除,如下所示:

    # Set up the variables
    test = ['aac', 'aad', 'aac', 'asd', 'msc']
    found = []
    # Loop Over the range of the lenght of the set
    for i in range(len(test)):
        try:
            if test[i].startswith(test[i+1][0:2]):
                found.append(test[i])  # Add the found item to the found list
        except IndexError: # You'll hit this when you do test[i+1]
            pass
    
    # Remove the Items at this point so you don't cause any issues
    for item in found:
        test.remove(item)  # If an item has been found remove the first instance
    
    # This sholuld output only ['aac', 'asd', 'msc']
    print test
    
    编辑:

    根据Martins的评论,您不需要再列出需要删除的项目,您可以按如下方式列出不需要删除的项目:

    # Set up the variables
    test = ['aac', 'aad', 'aac', 'asd', 'msc']
    found = []
    
    # Loop Over the range of the lenght of the set
    for i in range(len(test)):
        try:
            if not test[i].startswith(test[i+1][0:2]):
                found.append(test[i])  # Add the found item to the found list
        except IndexError: # You'll hit this when you do test[i+1]
            found.append(test[i]) # If there is no test[i+1], test[i] must be cool.
    
    
    # This sholuld output only ['aac', 'asd', 'msc']
    print found
    

    正如其他人所说,当您删除项目时,列表会变短,从而导致索引错误

    与原问题保持一致。如果您希望使用list.remove()删除项目,则可以将找到的项目添加到列表中,然后对其进行迭代,并将其从原始列表中删除,如下所示:

    # Set up the variables
    test = ['aac', 'aad', 'aac', 'asd', 'msc']
    found = []
    # Loop Over the range of the lenght of the set
    for i in range(len(test)):
        try:
            if test[i].startswith(test[i+1][0:2]):
                found.append(test[i])  # Add the found item to the found list
        except IndexError: # You'll hit this when you do test[i+1]
            pass
    
    # Remove the Items at this point so you don't cause any issues
    for item in found:
        test.remove(item)  # If an item has been found remove the first instance
    
    # This sholuld output only ['aac', 'asd', 'msc']
    print test
    
    编辑:

    根据Martins的评论,您不需要再列出需要删除的项目,您可以按如下方式列出不需要删除的项目:

    # Set up the variables
    test = ['aac', 'aad', 'aac', 'asd', 'msc']
    found = []
    
    # Loop Over the range of the lenght of the set
    for i in range(len(test)):
        try:
            if not test[i].startswith(test[i+1][0:2]):
                found.append(test[i])  # Add the found item to the found list
        except IndexError: # You'll hit this when you do test[i+1]
            found.append(test[i]) # If there is no test[i+1], test[i] must be cool.
    
    
    # This sholuld output only ['aac', 'asd', 'msc']
    print found
    

    从技术上讲,他并不是在删除列表中的项目时对列表进行迭代。他正在迭代
    范围(len(test))
    并从
    test
    中删除项目,而不是在从中删除时迭代
    test
    。问题是每次他在
    test
    中杀死某个东西时,他都需要从
    范围(len(test))
    中弹出一个元素。此外,您仍在从
    test
    中删除该元素,这将再次导致相同的错误
    test
    test2
    以相同的大小开始。但是当您在
    test2
    中删除内容时,它的大小会缩小。这意味着
    test[i]
    test2[i]
    将不再引用同一个对象。因此,您可能仍然会在这里遇到索引错误。此外,
    test2=test
    使两个变量引用相同的列表,而不是
    test
    的两个单独副本。所以
    test2.re