7

这是一个非常简单的问题,但我似乎无法为它找到一个满意的答案。

在 Python 中,最好的方法是使列表的最后一项成为第一个“推动”列表其余部分的项。

做的事情:

>>> a=[1,2,3,4]
>>> a[?????]
[4, 1, 2, 3]

我知道我总是可以玩len,列表连接......

>>> a=[1,2,3,4]
>>> [a[len(a)-1]] + a[0:len(a)-1]
[4, 1, 2, 3]

但这看起来不对……“ Pythonic ”,如果可以的话

先感谢您。

4

4 回答 4

13

切片比这更聪明一点;您可以使用索引从末尾开始计数:

a[-1:] + a[:-1]

演示:

>>> a=[1,2,3,4]
>>> a[-1:] + a[:-1]
[4, 1, 2, 3]

这适用于要移动到前面的任意数量的元素:

>>> a[-2:] + a[:-2]
[3, 4, 1, 2]

像这样使用切片在速度上与使用.insert()+相当.pop()(在一个简短的列表中):

>>> timeit.timeit('a[-1:] + a[:-1]', 'a=[1,2,3,4]')
0.59950494766235352
>>> timeit.timeit('a.insert(0,a.pop(-1))', 'a=[1,2,3,4]')
0.52790379524230957

但是如果您需要移动多个元素,则可以胜出:

>>> timeit.timeit('a[-2:] + a[:-2]', 'a=[1,2,3,4]')
0.58687901496887207
>>> timeit.timeit('a.insert(0,a.pop(-1));a.insert(0,a.pop(-1))', 'a=[1,2,3,4]')
1.0615170001983643
于 2012-10-11T17:23:44.687 回答
8

你可能想看看deque,如果你做了很多这样的事情,它们已经过优化(内存方面)来做你所要求的。

from collections import deque

>>> a = deque([1,2,3,4])
>>> a.rotate(1)
... deque([4, 1, 2, 3])

因为我们要timeit比较...

>>> setup = """from collections import deque
               a = deque([1,2,3,4])"""
>>> print timeit.timeit('a.rotate(1)', setup=setup)
... 0.219103839131
于 2012-10-11T17:36:24.027 回答
8
In [103]: a=[1,2,3,4]

In [104]: a.insert(0,a.pop(-1)) # pop(-1) removes the last element 
                                # and use insert() to insert the popped
                                #  element at 0th endex

In [105]: a
Out[105]: [4, 1, 2, 3]
于 2012-10-11T17:24:11.577 回答
0

如果您只需要转储任意访问的列表,正如您在@kreativitea 的评论中提到的那样,甚至可能不需要重新排序,您可以设计一个任意访问生成器:

size = 10
l = range(size)


# use a generator expression to yield slices of the list according 
# to your own order.
# note that no error checking is enforced, and that overlapping 
# and invalid accessRanges will work, so depending on the usage
# you have for this function, you might want to add some 
# sanity checks, like ensuring no overlap between accessRanges
# and that each item is accessed only once.
def ArbitraryListAccessor(listObj, accessRanges):
    for ar in accessRanges:
        for item in listObj[ar[0]:ar[1]]:
            yield item

# to dump the access-ordered list generator as a real list, you need to
# iterate over it, for example, with a list comprehension:
[i for i in ArbitraryListAccessor(l, ((-1,None), (0,-1)))]
# [9, 0, 1, 2, 3, 4, 5, 6, 7, 8]

它比双端队列慢,但比创建新列表快。对于多次迭代,它的速度大约是双端队列的两倍,但是对于单次运行(例如,只需以任意顺序读取列表一次),它是相当的(例如微秒级)。

这里的好处是您可以定义要使用的任何随机访问范围。您还可以用对象替换函数中的范围Slice并将其实现为常规列表切片(但是您已经提供了切片元组或切片对象。)

于 2012-10-11T19:15:30.370 回答