我teaching myself algorithms。我需要在列表中交换两个项目。 Python使一切变得简单:
def swap(A, i, j):
A[i], A[j] = A[j], A[i]
这是一种享受:
>>> A = list(range(5))
>>> A
[0, 1, 2, 3, 4]
>>> swap(A, 0, 1)
>>> A
[1, 0, 2, 3, 4]
请注意,该函数对退化情况i = j
具有弹性。正如您所期望的那样,它只会使列表保持不变:
>>> A = list(range(5))
>>> swap(A, 0, 0)
>>> A
[0, 1, 2, 3, 4]
后来我想在列表中置换三个项目。我写了一个函数来在3个循环中置换它们:
def cycle(A, i, j, k):
A[i], A[j], A[k] = A[j], A[k], A[i]
这很有效:
>>> A = list("tap")
>>> A
['t', 'a', 'p']
>>> cycle(A, 0, 1, 2)
>>> A
['a', 'p', 't']
然而,我(最终)发现它在堕落的情况下出错了。我假设一个退化的3周期将是一个交换。这是i = j
,cycle(i, i, k) ≡ swap(i, k)
:
>>> A = list(range(5))
>>> cycle(A, 0, 0, 1)
>>> A
[1, 0, 2, 3, 4]
但当i = k
发生其他事情时:
>>> A = list(range(5))
>>> sum(A)
10
>>> cycle(A, 1, 0, 1)
>>> A
[1, 1, 2, 3, 4]
>>> sum(A)
11
发生了什么? sum
在任何排列下都应该是不变的!为什么这种情况i = k
退化的方式不同?
我怎样才能实现我想要的目标?这是一个3周期函数,如果只有2个索引是不同的cycle(i, i, j) ≡ cycle(i, j, i) ≡ cycle(i, j, j) ≡ swap(i, j)
答案 0 :(得分:23)
cycle
正在按照你的要求行事:指定左手值右手值。
def cycle(A, i, j, k):
A[i], A[j], A[k] = A[j], A[k], A[i]
在功能上等同于
def cycle(A, i, j, k):
new_values = A[j], A[k], A[i]
A[i], A[j], A[k] = new_values
所以当你cycle(A, 1, 0, 1)
做你想说的是你想要的时候
A[1] = previous_A[0]
A[0] = previous_A[1]
A[1] = previous_A[1]
如果你想让循环按顺序工作,那么你必须按顺序编写它,否则python会评估右手,然后将其扩展到左边的参数。
答案 1 :(得分:11)
似乎你正在重新分配到同一目标 A[1]
,以获得呼叫的可视化:
A[1], A[0], A[1] = A[0], A[1], A[1]
请记住,来自 assignment statements :
的文档赋值语句评估表达式列表(请记住,这可以是单个表达式或以逗号分隔的列表,后者产生元组)并且将单个结果对象分配给每个目标列表,从左到右。
所以你的评价就像dis:
A[0], A[1], A[1]
的元组,转换为(0, 1, 1)
A[1], A[0], A[1]
。 从左到右分配:
A[1] = 0
A[0] = 1
A[1] = 1
所以第一个作业是A[1]
,第一个元素是元组0
,第二个作业是A[0]
第二个元素1
,最后是最后,使用元组中的第三个元素 A[1]
覆盖1
。
您可以使用 dis.dis
获得更多错综复杂的视图。注意如何首先加载赋值语句右边的所有元素,然后将它们分配给它们的值:
dis.dis(cycle)
2 0 LOAD_FAST 0 (A)
3 LOAD_FAST 2 (j)
6 BINARY_SUBSCR
7 LOAD_FAST 0 (A)
10 LOAD_FAST 3 (k)
13 BINARY_SUBSCR
14 LOAD_FAST 0 (A)
17 LOAD_FAST 1 (i)
20 BINARY_SUBSCR # Loading Done
21 ROT_THREE
22 ROT_TWO
23 LOAD_FAST 0 (A) # Assign first
26 LOAD_FAST 1 (i)
29 STORE_SUBSCR
30 LOAD_FAST 0 (A) # Assign second
33 LOAD_FAST 2 (j)
36 STORE_SUBSCR
37 LOAD_FAST 0 (A) # Assing third
40 LOAD_FAST 3 (k)
43 STORE_SUBSCR
44 LOAD_CONST 0 (None)
47 RETURN_VALUE
答案 2 :(得分:3)
由于cycle(A, 1, 0, 1)
变为A[1], A[0], A[1] = A[0], A[1], A[1]
,导致A[0]
和A[1]
以A[1]
的旧值结束。 cycle(0, 0, 1)
有效,因为它变为A[0], A[0], A[1] = A[0], A[1], A[0]
,相当于swap(A, k, j)
。