在Python列表中交换元素的最快方法

50

有没有比Python中下面这种方式更快的方法来交换两个列表元素:

L[a], L[b] = L[b], L[a]

我需要使用CythonWeave等工具吗?


1
不开玩笑,我正在实现一个算法,这个过程会重复数十亿次(根据问题的规模),想知道有没有什么简单的方法可以加快速度。 - Gerald Senarclens de Grancy
2
在尝试加速这个特定的交换之前,可能有很多方法可以加速您的程序。一些背景信息可能会很有趣。 - kriss
1
在我的硕士项目中,我曾经处理过类似的TSP局部搜索问题,我可以告诉你,你需要选择比2-Opt更好的算法,并且Psyco(或Cython等)是你的朋友。 - Brandon
2
Gerald,如果你有兴趣的话,我认为我还有一个简单的Tkinter GUI,可以读取TSPLIB问题并在单独的线程中显示它们的解决方案(通过2-Opt)。这对于可视化算法是否正常运行很有帮助。 - Brandon
1
@UkuLoskit: 不要做恶劣的人。 - Jossie Calderon
显示剩余10条评论
4个回答

132

看起来Python编译器使用这个结构来优化掉了临时元组:

代码:

import dis

def swap1():
  a=5
  b=4
  a, b = b, a

def swap2():
  a=5
  b=4
  c = a
  a = b
  b = c

print 'swap1():'
dis.dis(swap1)
print 'swap2():'
dis.dis(swap2)

输出:

swap1():
  6           0 LOAD_CONST               1 (5)
              3 STORE_FAST               0 (a)

  7           6 LOAD_CONST               2 (4)
              9 STORE_FAST               1 (b)

  8          12 LOAD_FAST                1 (b)
             15 LOAD_FAST                0 (a)
             18 ROT_TWO             
             19 STORE_FAST               0 (a)
             22 STORE_FAST               1 (b)
             25 LOAD_CONST               0 (None)
             28 RETURN_VALUE        
swap2():
 11           0 LOAD_CONST               1 (5)
              3 STORE_FAST               0 (a)

 12           6 LOAD_CONST               2 (4)
              9 STORE_FAST               1 (b)

 13          12 LOAD_FAST                0 (a)
             15 STORE_FAST               2 (c)

 14          18 LOAD_FAST                1 (b)
             21 STORE_FAST               0 (a)

 15          24 LOAD_FAST                2 (c)
             27 STORE_FAST               1 (b)
             30 LOAD_CONST               0 (None)
             33 RETURN_VALUE        

使用两个加载、一个 ROT_TWO 操作和两个保存,相比于三个加载和三个保存,更加高效。


22
先生,您刚刚向我展示了我热爱Python的又一个原因。我以前不知道“dis”是什么。 - Mike Lyons
2
太棒了!!感谢您告诉我们这件事。 - Piyush Kansal

3
如果您能发布一个代表性的代码示例,我们可以更好地对您的选项进行基准测试。值得一提的是,在以下愚蠢的基准测试中,我使用Shed Skin获得了约3倍的加速效果,并使用PyPy获得了约10倍的加速效果。
from time import time

def swap(L):
    for i in xrange(1000000):
        for b, a in enumerate(L):
            L[a], L[b] = L[b], L[a]

def main():
    start = time()
    L = list(reversed(range(100)))
    swap(L[:])
    print time() - start
    return L

if __name__ == "__main__":
    print len(main())

# for shedskin:
# shedskin -b -r -e listswap.py && make
# python -c "import listswap; print len(listswap.main())"

谢谢尝试 Shedskin。当我尝试这个程序时,我看到了大约 100 倍的加速。你还记得你使用的 Shedskin 版本吗? - user763227

0

我尝试了这种方法,它是在列表中交换两个数字的最简单的方法:

lst= [23, 65, 19, 90]
pos1 = lst.pop(0)
pos2 = lst.pop(1)
lst.append(pos1)
lst.append(pos2)
print(lst)

-5
我发现这个方法是交换两个数字最快的方式:
mylist   = [11,23,5,8,13,17];
first_el = mylist.pop(0)
last_el  = mylist.pop(-1)
mylist.insert(0, last_el)  
mylist.append(first_el)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接