将列表中所有元素向右移动一个位置的 Python 代码

5

我想把所有元素都向右移动,例如如果我有一个列表[1, 2, 3, 4, 5],它将变为[5, 1, 2, 3, 4]。基本上,最右边的元素会回到最左边,其他元素则向右移动。

这是我的代码:

length = len(values)
old_right = values[length - 1]
for j in range(length - 1, 0, -1):
    values[j] = values[j - 1]
values[0] = old_right

当我在IDLE中输入它时,最后一行的values[0]处(在values上有高亮标记),会出现一个错误,显示为“SyntaxError: invalid syntax”。我不知道为什么会出现这个错误。
此外,如何更改我的代码以使其从[5, 4, 3, 2, 1]返回到[1, 2, 3, 4, 5],即反转过程?
3个回答

12
>>> lst = [1, 2, 3, 4, 5]
>>> [lst[-1]] + lst[:-1]
[5, 1, 2, 3, 4]

反转:

>>> lst = [5, 1, 2, 3, 4]
>>> lst[1:] + [lst[0]]
[1, 2, 3, 4, 5]

编辑:

我以 [1, 2, 3, 4, 5] 为例,但我编写的代码可以适用于任何列表,无论它是什么,它都会将列表中最右边的值取到左边。在您的情况下,这确实有效,但只有在分配特定列表时才有效。我想知道如何使其适用于一般情况。

然后编写一个函数。

def shift_right(lst):
    try:
        return [lst[-1]] + lst[:-1]
    except IndexError:
        return lst

我喜欢你的方法,因为它更简单,但是如果你分配了一个列表,那么你的情况就会不同。对于我的情况,它只是适用于任何列表的一般情况,可以执行操作。 - JerryMichaels
3
你可以使用lst[-1:] + lst[:-1]代替[lst[-1]] + lst[:-1] - Renan Vilas Novas
@timgeb 在你的解决方案中添加反转列表的代码:[i for i in xrange(len(lst),0,-1)] - Renan Vilas Novas
2
@RenanV.Novas,为什么不直接使用lst[::-1]呢? - Padraic Cunningham
1
@PadraicCunningham,我不知道这个解决方案!太棒了! - Renan Vilas Novas
显示剩余3条评论

8
使用deque模块。
from collections import deque
a = deque([1,2,3,4,5]).rotate(1)

a = list(a)

这是理想的解决方案,因为它允许您将列表旋转任意数量的位置。如果您想要向另一个方向旋转它,则可以将参数设置为负数。
编辑:
目前被接受的答案比这种方法慢得多。deque数据结构针对在列表开头和末尾插入进行了优化,这比接受的答案的线性时间操作要快得多。这可能在OP使用代码的上下文中无关紧要,但在任何性能至关重要的情况下,deque是正确的选择。
我编写了一个小程序,将包含1,000,000个元素的列表向右旋转一个位置1,000次。以下是结果。
List Slicing: 0:00:12.043186
Deque: 0:00:00.028064

代码在这里。
import datetime
from collections import deque


start = datetime.datetime.now()

lst = [1]* 1000000

#first approach
for x in range(1000):
    lst = [lst[-1]] + lst[:-1]

end  = datetime.datetime.now()
print end - start

lst = deque(lst)
#second approach 
for y in range(1000):
    lst.rotate(1)
lst = list(lst)

start = datetime.datetime.now()
print start - end

我不认为这是理想的情况,因为你可以使用列表切片来完成同样的事情,而且不需要导入和/或将deque对象转换为列表。 - R Nar
好问题。不知道列表转换是否仍然是常数级的工作? - R Nar
简而言之,在使用切片时,您必须创建新列表以使其成为所需的内容。deque.rotate()通过使用数据结构属性(重置指针)来实现此目的。显然,这比移动元素更有效率。当然,如果算法需要一些deque不能提供的列表特定属性,例如随机内存访问,那么为什么会有人将deque()转换回列表呢?对于这个答案+1,尽管deque()不是一个模块:D。只是一个小的数据结构类。 - Dalen
对我来说速度不是问题,目的只是为了完成任务。我很感激您的详细解释,但我觉得有点更加混乱,而被接受的答案则更为简明扼要。 - JerryMichaels
1
@Erik,你可能会发现time模块比datetime模块更适合计时代码。 - Padraic Cunningham
显示剩余5条评论

2
a = [1,2,3,4,5]
x = a.pop()
a.insert(0, x)

这比切片更快。 - tdelaney
这也会改变原始列表。 - Padraic Cunningham
@PadraicCunningham,这确实是提高速度的一部分,跳过重新分配列表的需要。尽管原始问题没有任何要求,但它的示例显示了就地更新。 - tdelaney
@Dalen - timeit 告诉我在一个百万成员列表上,这个方法快了20倍。你的测量结果是什么? - tdelaney
但是,list.insert() 强制将所需索引后的所有元素向右移动,从而再次执行 malloc。有时必须复制整个列表。如果不使用 deque(),我同意这是正确的方法。 - Dalen
显示剩余5条评论

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