1

我是 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'但实际上,这会引发IndexError. 此外,我无法达到预期的结果。你能解释一下吗?

4

4 回答 4

2

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

移动,因为项目从当前索引的列表中删除,列表索引的其余部分shift ; 索引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

现在i针对每个循环迭代的i长度进行测试,并且我们仅在没有元素被删除时才增加。请注意,循环限制为长度减 1,因为您要测试test[i + 1]每次迭代。

请注意,我使用del test[i]; 无需再次扫描列表搜索要删除的;如果值在列表中出现多次但仅应删除后面的实例,这也可能导致细微的错误;例如['aac', 'foo', 'aac', 'aad']应该导致['aac', 'foo', 'aad'], not ['foo', 'aac', 'aad'] , 这就是test.remove(test[i])会导致的结果。

演示:

>>> 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
... 
>>> test
['aac', 'asd', 'msc']

您可以使用列表推导来避免缩小列表问题:

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

这两种方法都只需要一个循环通过输入列表。

于 2013-10-11T07:13:21.710 回答
2

当您从列表中删除项目时,range(len(test))仍然具有相同的值。因此,即使您的test列表只剩下任何项目,循环仍在进行。

我有两个解决方案:

  1. 将您想要的项目复制到新列表中,而不是删除它:

    test2 = test[i]
    

    并且不要忘记反转条件。

  2. 向后循环。像这样:

    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])
    

希望能帮助到你!

PS对不起我的愚蠢,以前的回答

于 2013-10-11T07:00:53.907 回答
1

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

与原始问题保持一致。如果您希望使用 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
于 2013-10-11T07:27:52.817 回答
0

for i in range(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

相反,您可以做的是累积您想要删除的事物的索引并在以后删除它们:

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]

输出

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']
于 2013-10-11T07:12:42.997 回答