你能告诉我为什么我必须在try / except语句中包含这个if
吗?
当我使用list调用函数时,此方法引发IndexError,其中最后一个元素与列表中的其他元素相同。当最后一个元素在列表中只显示一次时,不会引发IndexError。
def unique(n):
for i in range(len(n) - 1, -1, -1):
for j in range(i):
try:
if n[i] == n[j]:
n.pop(i)
except:
pass
return n
>>unique([1, 2, 3, 2, 4])
[1, 2, 3, 4]
>>unique([1, 2, 3, 4, 2])
IndexError
在if
语句中没有try / except:
>>print n[i]
2
>>n.pop(i)
IndexError
>>del n[i]
IndexError
同样围绕n.pop(i)
使用try / except并不起作用,我不得不用它包围整个if
。为什么?
答案 0 :(得分:1)
当您迭代迭代时,您正在更改迭代,这从根本上是错误的并且可能导致未定义的行为。这样做的行为是您正在修改列表长度而不通知迭代器更改。迭代次数仍然等于列表的原始长度,但实际的元素数量可能更低(如果没有重复,则可以)。
访问Python中不存在的索引通常会引发IndexError。你的try / except块会抑制它,但迭代仍将继续超过原始长度。
可能的解决方案实际上是使用一个集合,它将为您处理唯一性:
def unique(n):
return list(set(n))
或者,保留您的迭代解决方案,创建一个空列表或您将分配结果的列表副本。为了减少时间复杂度,可以将唯一数据存储为dict,其中赋值是恒定时间:
def unique(n):
uniques = {}
for i in range(len(n) - 1, -1, -1):
uniques[n[i]] = n[i]
return list(uniques.keys())
如果您关心按键外观的顺序,OrderedDict可以派上用场。
from collections import OrderedDict
def unique(n):
return list(OrderedDict.fromkeys(n))
答案 1 :(得分:1)
我不相信你的
>>print n[i]
2
>>n.pop(i)
IndexError
示范。无论如何,当你发现索引i
包含重复并删除它时,你也可以打破内循环,而不是try / except。毕竟,这是内循环的唯一工作。然后你也不会得到错误,这恰好来自于你已经删除它后继续并尝试访问n[i]
。
def unique(n):
for i in range(len(n) - 1, -1, -1):
for j in range(i):
if n[i] == n[j]:
n.pop(i)
break
return n