如何在Python中反转列表的一部分(切片)?

48
为什么这个不起作用?
# to reverse a part of the string in place 
a = [1,2,3,4,5]
a[2:4] = reversed(a[2:4])  # This works!
a[2:4] = [0,0]             # This works too.
a[2:4].reverse()           # But this doesn't work
8个回答

62

只需使用切片并反转它。

a[2:4] = a[2:4][::-1]

7
唯一的缺点是它不是原地操作,即它将使用额外的内存。 - Yatharth Varshney

24

a[2:4] 创建了所选子列表的复制品,而 a[2:4].reverse() 反转该复制品。这不会改变原始列表。 Python 列表切片总是创建副本 -- 您可以使用

b = a[:]

复制整个列表。


3
@İsmail: 我没有看到可变性和切片创建副本之间的联系。切片NumPy数组不会创建副本,并且它们也是可变的。这些是独立的设计决策。 - Sven Marnach
@İsmail:我似乎不明白你想要什么。如果Python列表是不可变的,你无论如何都无法更改它,因此你无法确定是否创建了副本。 - Sven Marnach
1
注意:“切片 Python 列表总是创建副本”——除非像 OP 的示例中那样将它们分配给,例如 a[2:4] = reversed(a[2:4])。人们可能会认为 x = reversed(x)x.reverse() 都修改了 x,但在 Python 中,它们是根本不同的操作,当 x 不是变量时,它们的结果也不同,如此处所示。 - musiphil

13

你可以考虑另外一种方法,使用切片的反向索引:

a[2:4] = a[3:1:-1]

1
虽然这个方法可以工作,但是没有办法使用这个确切的方法来反转包含第一个元素的切片。 - quintopia
4
这句话的意思是:实际上可以省略第一个索引,如 assert a[3::-1] == [4, 3, 2, 1]。它的作用是倒序输出从第四个元素开始到第一个元素的列表。 - VMAtm
@VMAtm 说得好。我现在知道了,但当时不知道。不过这确实指向了语言中某种正交性的缺失,是吧? - quintopia
1
对我来说,这只是一种惯例,如果你在 spolyce 中省略第二个(或第一个)索引,你只需说“从开头到结尾”,无需计算这些索引。 - VMAtm

6

我认为值得进一步阐述其原因。

a[2:4].reverse()

似乎无法工作。

除了 a[2:4] 在内存中创建副本的事实之外,还应注意到

list.reverse()

该方法原地(in place)翻转列表,返回类型为None。如果您执行

print(a[2:4].reverse())

显然,如果你强制执行,会打印出None
a[2:4] = a[2:4].reverse()

如果使用 a[2:4][::-1] 来翻转列表切片,Python 会抛出 TypeError 异常。然而,内存中确实存在一个已经被翻转的 a[2:4] 的副本,只是您无法访问它。

另一方面,a[2:4] = reversed(a[2:4]) 可以工作,因为 reversed() 返回一个反向迭代器。

有关当出现在赋值符号左侧时,a[2:4] 如何不同,请参阅被接受的答案的注释。


其实很重要的一点是,arr[i:j].reverse() 的返回类型是 None - Hemanth Kollipara

2

纯粹地在原地完成此操作的一种方法是使用传统的循环:

def reverse(seq, start, stop):
    size = stop + start
    for i in range(start, (size + 1) // 2):
        j = size - i
        seq[i], seq[j] = seq[j], seq[i]


l = list(range(10))
print(l)
# [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

reverse(l, 2, 5)
print(l)
# [0, 1, 5, 4, 3, 2, 6, 7, 8, 9]

1

以下是使用切片和列表基础知识的奇怪示例和更奇怪的解决方案。

问题:将列表按两个一组反转。

输入:[1,2,3,4,5,6]

输出:[3,2,1,6,5,4]

解决方案:

[item for i in range(0,len(l),len(l)/2) for item in l[i:i+len(l)/2][::-1]]

问题: 反转某人的名字中的字母。

例如:Harry Porter

输出: yrraH retroP

解决方案:

' '.join(map(lambda x:x[::-1], s.split()))

1

a[2:4] 是列表 a 的一个副本,它是使用列表 a 中的第 2、3、4 个项目构建的。前两个可以工作,因为您将更改分配到原始列表中的那些位置。最后一个不起作用,因为您没有影响原始列表。


0

如果要将数组从特定索引位置反转到另一个位置,请使用以下代码:

#start is the starting index
#end is the ending index
while start<end:
    nums[start],nums[end] = nums[end],nums[start]
    start+=1
    end-=1

这段代码的作用是从开头和结尾分别选取一个元素并进行交换,然后将起始指针向前移动,同时将结束指针向后移动。

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