Python列表旋转

112
我想将Python列表向右或向左旋转任意数量的项目(后者使用负数参数)。 类似这样的东西:
>>> l = [1,2,3,4]
>>> l.rotate(0)
[1,2,3,4]
>>> l.rotate(1)
[4,1,2,3]
>>> l.rotate(-1)
[2,3,4,1]
>>> l.rotate(4)
[1,2,3,4]

这该怎么做?


3
我不使用Python,但是如果你有一个push/pop方法,你可以使用l.push(l.pop())。然后对它进行循环处理,这样就可以向前移动了。 - Ryan Amos
1
感谢提供其他问题的链接。我尝试在Google和SO上搜索“python列表旋转”,但没有找到任何相关内容。这个问题可能会成为那些想要“旋转”而不是“移位”的人的着陆页面。 - Drew Noakes
1
@DrewNoakes:在“python list rotate”的SO搜索结果的第一页中,两者都显示出来。我想需要使用单词的缩写形式。;-) - DSM
3
另一个问题特别关注效率;而这个问题可能涉及略有不同的领域。 - Aaron Dufour
4
这个“重复”的内容以及这里的回答比原始内容更有用。谢谢! - mdandr
显示剩余5条评论
4个回答

202
def rotate(l, n):
    return l[-n:] + l[:-n]

更传统的做法:

def rotate(l, n):
    return l[n:] + l[:n]

示例:

example_list = [1, 2, 3, 4, 5]

rotate(example_list, 2)
# [3, 4, 5, 1, 2]
rotate的参数是一个列表和一个整数,表示位移量。该函数使用分片创建两个新列表,并返回这些列表的连接。 rotate函数不会修改输入列表。

很不错且简单。但它的旋转方向与问题中指定的相反。 - Drew Noakes
1
@S.Lott:有人可能会认为OP在他的示例中方向是相反的。大多数关于列表旋转的Python教程都使用与E先生的第一个旋转函数相同方向的符号约定。 - the wolf
12
我会加上 n = n % len(n),以使其适用于 n > len(n) 的情况。 - user1071136
有没有不用return的方法呢?我尝试了 l=l[n:] + l[:n],但当我试图返回 l 时,我得到的还是原来的那个。 - GinKin
2
不确定您的意思。该函数不修改输入参数,它返回一个新列表。最好针对您的问题提出一个新问题。 - YXD
13
@user1071136 我想你的意思是 n = n % len(l) - ktbiz

128

如果适用的话,您可以使用 collections.deque 作为解决方案:

import collections

d = collections.deque([1,2,3,4,5])
d.rotate(3)

print d
>>> deque([3, 4, 5, 1, 2])

作为额外的好处,我希望它比内置列表更快。


14
对于未来的读者:根据https://wiki.python.org/moin/TimeComplexity,`collections.deque rotate()`比切片更快。 - Geoff
应该提到集合默认向左旋转吗? - QuestionEverything
5
deque.rotate函数将deque队列向右旋转,具体用法可以参考Python官方文档中的collections.deque.rotate部分。 - miles82

28

以下函数将把列表l向右旋转x个位置:

def rotate(l, x):
  return l[-x:] + l[:-x]

请注意,只有当 x 超出范围 [-len(l), len(l)] 时,此代码才会返回原始列表。若要使其适用于所有值的 x,请使用以下代码:

def rotate(li, x):
  return li[-x % len(li):] + li[:-x % len(li)]

有没有不用 return 的方法?我尝试了 l=l[n:] + l[:n] 但是当我尝试返回 l 时,我得到的是原始值。 - GinKin
@GinKin 为什么没有返回值?这是从函数中返回东西的方式。我的意思是,你可以使用lambda,但那只会使返回值隐式化。 - Aaron Dufour
我想让它“原地”进行,这样它就不会返回任何东西,如果我在运行函数后键入>>> l,我将得到旋转后的列表,而不是原始列表。 - GinKin
2
@GinKin,你可以使用l[:] = ...代替return ...,这样就可以直接在原地修改了。但我不建议这样做。 - Aaron Dufour
为什么不呢? - GinKin
1
在Python中,函数通常被期望是无副作用的;如果一个参数是方法的第一个(self)参数,那么通常只会更改其中一个参数。这只是一种约定而已。 - Aaron Dufour

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

关于将一个数组整体向左旋转n个位置(在调用rotate时传入正数y表示向左旋转,在传入负数y时表示向右旋转),可以按照以下方法进行:

def rotate(l, y=1):
   if len(l) == 0:
      return l
   y = y % len(l)    # Why? this works for negative y

   return l[y:] + l[:y]

如果您希望旋转方向与您的示例相同,只需在旋转中否定y

def rotate(l, y=1):
   if len(l) == 0:
      return l
   y = -y % len(l)     # flip rotation direction

   return l[y:] + l[:y]

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