顺序在Python的交换符号中是否重要? (a,b = b,a)

时间:2019-11-28 04:04:34

标签: python

我一直在解决一个类似于下面的编码面试问题:

给出一个字符数组A和一个整数数组P,其中P [i]表示元素在置换中i处的位置。例如,当A = <a, b, c, d>P = <2, 0, 1, 3>时,A应该变成<b, c, a, d>

我对此的解决方案如下:

for i in range(len(A)):
    while perm[i] != i:
        A[i], A[perm[i]] = A[perm[i]], A[i]
        perm[i], perm[perm[i]] = perm[perm[i]], perm[i]

这一个给了我无限循环,而下面的一个起作用了

for i in range(len(A)):
    while perm[i] != i:
        A[perm[i]], A[i] = A[i], A[perm[i]] 
        perm[perm[i]], perm[i] = perm[i], perm[perm[i]]

我一直认为Python交换快捷方式中的顺序无关紧要,但是我很困惑为什么上面的那个不起作用而下面的那个很好用。

有什么想法吗?

2 个答案:

答案 0 :(得分:6)

顺序很重要 ,并且您在结束时创建了代码。在进行任何赋值之前,都会完全计算整个右侧,因此在简单的情况下,这无关紧要。但是比较:

perm[i], perm[perm[i]] = perm[perm[i]], perm[i]

收件人:

perm[perm[i]], perm[i] = perm[i], perm[perm[i]]

在分配给perm[i]时,第一个分配给perm[i]的值会影响来自perm[perm[i]]的值 read ;在第二步中,对perm[perm[i]]的赋值使用perm[i] old 值确定分配位置,然后 then 赋新的{{ 1}}。

发生这种情况是因为分配是从左到右执行的;采取的步骤依次为:

    正确构建了所有
  1. perm[i]值(当前解释器中未构建实际的tuple,但这在逻辑上是发生的)
  2. 发生向左目标的分配(包括确定分配位置所需的所有读取)
  3. 任务进行到正确的目标

基本上,您遇到了问题,因为您都在分配的侧以不同的顺序读写相同的值。

答案 1 :(得分:1)

是的,这里的顺序很重要,因为您正在更改从同一列表读取的索引处列表perm的内容。如果相同索引处的值发生变化,则以不同的顺序分配可以得出不同的结果。

这是它编译成的字节码:顺序为(读,读,读,写,读,写)。

>>> dis.dis('perm[i], perm[perm[i]] = perm[perm[i]], perm[i]')
  1           0 LOAD_NAME                0 (perm)
              3 LOAD_NAME                0 (perm)
              6 LOAD_NAME                1 (i)
              9 BINARY_SUBSCR                          # reads from perm
             10 BINARY_SUBSCR                          # reads from perm
             11 LOAD_NAME                0 (perm)
             14 LOAD_NAME                1 (i)
             17 BINARY_SUBSCR                          # reads from perm
             18 ROT_TWO
             19 LOAD_NAME                0 (perm)
             22 LOAD_NAME                1 (i)
             25 STORE_SUBSCR                           # writes to perm
             26 LOAD_NAME                0 (perm)
             29 LOAD_NAME                0 (perm)
             32 LOAD_NAME                1 (i)
             35 BINARY_SUBSCR                          # reads from perm
             36 STORE_SUBSCR                           # writes to perm
             37 LOAD_CONST               0 (None)
             40 RETURN_VALUE

这是另一种方式:顺序是(读,读,读,读,写,写)。

>>> dis.dis('perm[perm[i]], perm[i] = perm[i], perm[perm[i]]')
  1           0 LOAD_NAME                0 (perm)
              3 LOAD_NAME                1 (i)
              6 BINARY_SUBSCR                          # reads from perm
              7 LOAD_NAME                0 (perm)
             10 LOAD_NAME                0 (perm)
             13 LOAD_NAME                1 (i)
             16 BINARY_SUBSCR                          # reads from perm
             17 BINARY_SUBSCR                          # reads from perm
             18 ROT_TWO
             19 LOAD_NAME                0 (perm)
             22 LOAD_NAME                0 (perm)
             25 LOAD_NAME                1 (i)
             28 BINARY_SUBSCR                          # reads from perm
             29 STORE_SUBSCR                           # writes to perm
             30 LOAD_NAME                0 (perm)
             33 LOAD_NAME                1 (i)
             36 STORE_SUBSCR                           # writes to perm
             37 LOAD_CONST               0 (None)
             40 RETURN_VALUE

因此第一个能够读取在同一行中写入的值,因为它先写入后再读取。但是第二个则不能,因为它会在写入任何内容之前先进行所有读取。

老实说,我认为您永远不应该编写这样的代码,因为即使运气很好,它也会使您感到困惑,这并不令人理解-应该应该做什么,更不用说了它做什么。声明一个j = perm[i]之类的变量,然后编写perm[i], perm[j] = perm[j], perm[i],该代码将易于理解,而且绝对不是魔术。