如何解决在迭代期间交换列表元素
我在几个地方读到过在迭代期间修改数组/列表是不好的做法。然而,许多常见的算法似乎都做到了这一点。例如冒泡排序、插入排序以及下面的示例,用于查找对列表进行排序所需的最小交换次数。
在迭代期间交换列表项是规则的例外吗?如果是为什么?
在这方面,enumerate
和简单的 for i in range(len(arr))
循环之间发生的情况有区别吗?
def minimumSwaps(arr):
ref_arr = sorted(arr)
index_dict = {v: i for i,v in enumerate(arr)}
swaps = 0
for i,v in enumerate(arr):
print("i:",i,"v:",v)
print("arr: ",arr)
correct_value = ref_arr[i]
if v != correct_value:
to_swap_ix = index_dict[correct_value]
print("swapping",arr[to_swap_ix],"with",arr[i])
# Why can you modify list during iteration?
arr[to_swap_ix],arr[i] = arr[i],arr[to_swap_ix]
index_dict[v] = to_swap_ix
index_dict[correct_value] = i
swaps += 1
return swaps
arr = list(map(int,"1 3 5 2 4 6 7".split(" ")))
assert minimumSwaps(arr) == 3
解决方法
一个数组在迭代时不应该被修改,因为迭代器不能处理变化。但是还有其他方法可以遍历数组,而无需使用迭代器。
这是使用迭代器:
for index,item in enumerate(array):
# don't modify array here
这是没有迭代器的:
for index in range(len(array)):
item = array[index]
# feel free to modify array,but make sure index and len(array) are still OK
如果修改数组时需要修改长度和索引,那就更“手动”了:
index = 0
while index < len(array):
item = array[index]
# feel free to modify array and modify index if needed
index += 1
,
修改列表中的项目有时会产生意想不到的结果,但如果您了解这些影响,那就完全没问题了。这并非不可预测。
您需要了解它不是您正在迭代的原始列表的副本。下一项始终是列表中下一个索引上的项目。因此,如果您在迭代器到达之前更改索引中的项目,则迭代器将产生新值。
这意味着,例如,如果您打算通过将 index+1 处的 item 设置为 enumerate() 产生的当前值,将所有项目向上移动一个索引。然后你会得到一个完全填满最初在索引 0 上的项目的列表。
a = ['a','b','c','d']
for i,v in enumerate(a):
next_i = (i + 1) % len(a)
a[next_i] = v
print(a) # prints ['a','a','a']
如果您在迭代时向列表追加和插入项目,您可能永远不会到达终点。
在您的示例中,正如您在许多算法中指出的,例如组合和排序,它是算法的一部分来改变即将到来的项目。
for i in range(len(arr))
中的范围内的迭代器不会适应原始列表中的更改,因为范围是在开始之前创建的并且是不可变的。因此,如果列表的开头长度为 4,则无论列表长度如何变化,循环都会尝试精确迭代 4 次。
# This is probably a bad idea
for i in range(len(arr)):
item = arr[i]
if item == 0:
arr.pop()
# This will work (don't ask for a use case)
for i,item in enumerate(arr):
if item == 0:
arr.pop()
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。