关键问题在于
for
循环具有固定的迭代次数,但是当你在循环内删除列表时,你正在
缩小它们。因此,循环指针保持不变,而列表变得更小。最终,循环无法完成迭代。
选项1
作为一个简单的解决方法,你可以在函数内部创建一个新列表。这应该更简单,并且不会改变你的原始列表。
def remove_from_list(l):
r = []
for e in l:
if isinstance(e, list):
r.append(remove_from_list(e))
return r
>>> remove_from_list([1, 2, [], [3,[4]], 5])
[[], [[]]]
此外,由于您只附加空结构,因此这比创建数据副本和后续的删除调用更快。
选项2
在wim的想法的基础上进行反向迭代,并使用del
如果您想要原地修改列表。
def remove_from_list(l):
r = []
for i in range(len(l) - 1, -1, -1):
if isinstance(l[i], list):
remove_from_list(l[i])
else:
del l[i]
>>> l = [1, 2, [], [3,[4]], 5]
>>> remove_from_list(l)
>>> l
[[], [[]]]
我建议从良好的实践角度出发,
要么返回一个副本,要么就直接修改而不返回,但不能两者都做。
您可以使用timeit比较来确定哪种方法在您的数据上运行得更快。
首先,是设置 -
def remove_from_list(l):
r = []
for e in l:
if isinstance(e, list):
r.append(remove_from_list(e))
return r
def remove_from_list_reverse_del(l):
r = []
for i in range(len(l) - 1, -1, -1):
if isinstance(l[i], list):
remove_from_list(l[i])
else:
del l[i]
def remove_from_list_copy(l):
for e in l[:]:
if isinstance(e, list):
remove_from_list_copy(e)
else:
l.remove(e)
return l
y = [1, 2, [], [3,[4]], 5]
z = copy.deepcopy(y * 10000)
接下来是时间安排 -
%timeit remove_from_list(z)
19.3 ms ± 334 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)
%%timeit
z2 = copy.deepcopy(z) # copying because this function mutates the original
remove_from_list_reverse_del(z2)
78.6 ms ± 157 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)
虽然在创建z2
时浪费了很多时间。
del
,不需要复制。 - wim