在python中旋转列表最有效的方法是什么? 现在我有这样的东西:

>>> def rotate(l, n):
...     return l[n:] + l[:n]
... 
>>> l = [1,2,3,4]
>>> rotate(l,1)
[2, 3, 4, 1]
>>> rotate(l,2)
[3, 4, 1, 2]
>>> rotate(l,0)
[1, 2, 3, 4]
>>> rotate(l,-1)
[4, 1, 2, 3]

有没有更好的办法?


当前回答

我是“老派”,我定义了最低延迟,处理器时间和内存使用效率,我们的克星是臃肿的库。所以只有一个正确的方法:

    def rotatel(nums):
        back = nums.pop(0)
        nums.append(back)
        return nums

其他回答

如果你只想遍历这些元素集,而不是构造一个单独的数据结构,可以考虑使用迭代器来构造一个生成器表达式:

def shift(l,n):
    return itertools.islice(itertools.cycle(l),n,n+len(l))

>>> list(shift([1,2,3],1))
[2, 3, 1]

我能想到的最简单的方法:

a.append(a.pop(0))

对于一个列表X = ['a', 'b', 'c', 'd', 'e', 'f'],并且shift值小于列表长度,我们可以如下所示定义函数list_shift()

def list_shift(my_list, shift):
    assert shift < len(my_list)
    return my_list[shift:] + my_list[:shift]

的例子,

list_shift (X, 1)返回(' b ', ' c ', ' d ', ' e ', ' f ', ' '] list_shift (X, 3)返回(' d ', ' e ', ' f ', ' ', ' b ', ' c ']

我想你想要的是这个:

a.insert(0, x)

关于时间安排的一些注意事项:

如果从列表开始,l.append(l.pop(0))是可以使用的最快方法。这可以单独用时间复杂度来证明:

双端队列。旋转是O(k) (k=元素数量) 列表到deque的转换是O(n) 列表。附加和列表。pop都是O(1)

所以如果你从deque对象开始,你可以deque.rotate(),代价是O(k)。但是,如果起始点是一个列表,那么使用deque.rotate()的时间复杂度是O(n)。l.append(l.pop(0)在O(1)处更快。

为了便于说明,这里有一些1M迭代的计时示例:

需要类型转换的方法:

双端队列。使用deque对象旋转:0.12380790710449219秒(最快) 双端队列。旋转类型转换:6.853878974914551秒 np。滚动nparray: 6.0491721630096436秒 np。滚带类型转换:27.558452129364014秒

列出这里提到的方法:

L.append (l.pop(0)): 0.32483696937561035秒(最快) "shiftInPlace": 4.819645881652832秒 ...

所用的计时代码如下。


collections.deque

显示从列表创建deques是O(n):

from collections import deque
import big_o

def create_deque_from_list(l):
     return deque(l)

best, others = big_o.big_o(create_deque_from_list, lambda n: big_o.datagen.integers(n, -100, 100))
print best

# --> Linear: time = -2.6E-05 + 1.8E-08*n

如果你需要创建deque对象:

1M次迭代@ 6.853878974914551秒

setup_deque_rotate_with_create_deque = """
from collections import deque
import random
l = [random.random() for i in range(1000)]
"""

test_deque_rotate_with_create_deque = """
dl = deque(l)
dl.rotate(-1)
"""
timeit.timeit(test_deque_rotate_with_create_deque, setup_deque_rotate_with_create_deque)

如果你已经有deque对象:

1M次迭代@ 0.12380790710449219秒

setup_deque_rotate_alone = """
from collections import deque
import random
l = [random.random() for i in range(1000)]
dl = deque(l)
"""

test_deque_rotate_alone= """
dl.rotate(-1)
"""
timeit.timeit(test_deque_rotate_alone, setup_deque_rotate_alone)

np.roll

如果你需要创建nparray

1百万次迭代@ 27.558452129364014秒

setup_np_roll_with_create_npa = """
import numpy as np
import random
l = [random.random() for i in range(1000)]
"""

test_np_roll_with_create_npa = """
np.roll(l,-1) # implicit conversion of l to np.nparray
"""

如果你已经有nparray:

1M次迭代@ 6.0491721630096436秒

setup_np_roll_alone = """
import numpy as np
import random
l = [random.random() for i in range(1000)]
npa = np.array(l)
"""

test_roll_alone = """
np.roll(npa,-1)
"""
timeit.timeit(test_roll_alone, setup_np_roll_alone)

“转移到位”

不需要类型转换

1M次迭代@ 4.819645881652832秒

setup_shift_in_place="""
import random
l = [random.random() for i in range(1000)]
def shiftInPlace(l, n):
    n = n % len(l)
    head = l[:n]
    l[:n] = []
    l.extend(head)
    return l
"""

test_shift_in_place="""
shiftInPlace(l,-1)
"""

timeit.timeit(test_shift_in_place, setup_shift_in_place)

l.append(l.pop(0))

不需要类型转换

1M迭代@ 0.32483696937561035

setup_append_pop="""
import random
l = [random.random() for i in range(1000)]
"""

test_append_pop="""
l.append(l.pop(0))
"""
timeit.timeit(test_append_pop, setup_append_pop)