为什么这个swap表达式不能按预期工作?

2024-03-29 06:10:45 发布

您现在位置:Python中文网/ 问答频道 /正文

这是我试图用Python编写的基本选择排序。你知道吗

arr = [64,12,35,312,45,12,50,80,0,4,6,8,92]
for i in range(len(arr)):
    arr[i], arr[arr.index(min(arr[i:]))] = arr[arr.index(min(arr[i:]))], arr[i]

但是,swap表达式不起作用。很明显,我对Python有一些不了解的地方。它是什么?你知道吗


Tags: inforindexlen排序表达式地方range
1条回答
网友
1楼 · 发布于 2024-03-29 06:10:45

这是因为首先计算r.h.s,然后在值解包期间,为l.h.s__setitem__上的每一项逐个调用。这意味着当计算l.h.sarr[arr.index(...)]时,第一个赋值arr[i] = arr[arr.index(...)]已经发生,因此修改了数组。因此,l.h.s.arr.index(...)不一定返回与r.h.s对应的值相同的值。你知道吗

我们可以通过以下代码片段将其可视化:

class Test:
    def __getitem__(self, x):
        print(f'get {x}')
        return x

    def __setitem__(self, x, y):
        print(f'set {x}={y}')


class Index:
    def __init__(self, x):
        self.x = x
        print(self)

    def __repr__(self):
        return f'{type(self).__name__}({self.x})'


test = Test()
test[Index(0)], test[Index(1)] = test[Index(2)], test[Index(3)]

输出:

Index(2)
get Index(2)
Index(3)
get Index(3)
Index(0)
set Index(0)=Index(2)
Index(1)
set Index(1)=Index(3)

同时检查docs about evaluation order of expressions。你知道吗

具体示例的更详细分解

对于您的特定示例,使用最小值的索引,这将导致不操作。以下是按顺序发生的步骤:

  1. 对R.h.s.arr.index(min(arr[i:]))进行求值(我们称之为m),然后对arr[m]进行求值(我们称之为a;这是arr[i:]的最小元素)。你知道吗
  2. R.h.s.arr[j]被计算(我们称之为b)。你知道吗
  3. 计算L.h.s.arr.__setitem__(i, a),将索引i处的元素设置为最小值(a)。你知道吗
  4. 评估L.h.s.arr.__setitem__(arr.index(min(arr[i:])), b)。由于前面的操作(3.)arr.index(min(arr[i:]))现在将是i。因此,索引i处的元素被设置为b,这是前一个arr[i],也就是说,它被设置回其前一个值,从而导致no-op

相反,您可以提前计算索引:

index = arr.index(min(arr[i:]))
a[i], a[index] = a[index], a[i]

相关问题 更多 >