Python 删除列表项时出现意外的索引器错误
我是Python的初学者。我以前学过其他语言,如C++(初学者)和jQuery。但是我发现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]) #
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