在迭代期间交换列表元素

如何解决在迭代期间交换列表元素

我在几个地方读到过在迭代期间修改数组/列表是不好的做法。然而,许多常见的算法似乎都做到了这一点。例如冒泡排序、插入排序以及下面的示例,用于查找对列表进行排序所需的最小交换次数

在迭代期间交换列表项是规则的例外吗?如果是为什么?

在这方面,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 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?
Java在半透明框架/面板/组件上重新绘画。
Java“ Class.forName()”和“ Class.forName()。newInstance()”之间有什么区别?
在此环境中不提供编译器。也许是在JRE而不是JDK上运行?
Java用相同的方法在一个类中实现两个接口。哪种接口方法被覆盖?
Java 什么是Runtime.getRuntime()。totalMemory()和freeMemory()?
java.library.path中的java.lang.UnsatisfiedLinkError否*****。dll
JavaFX“位置是必需的。” 即使在同一包装中
Java 导入两个具有相同名称的类。怎么处理?
Java 是否应该在HttpServletResponse.getOutputStream()/。getWriter()上调用.close()?
Java RegEx元字符(。)和普通点?