如何在适当的位置反转列表中的子列表?
Posted
技术标签:
【中文标题】如何在适当的位置反转列表中的子列表?【英文标题】:How do I reverse a sublist in a list in place? 【发布时间】:2014-04-11 00:32:58 【问题描述】:我应该创建一个函数,它的输入是一个列表和两个数字,该函数反转子列表,它的位置由两个数字指示。 例如这是它应该做的:
>>> lst = [1, 2, 3, 4, 5]
>>> reverse_sublist (lst,0,4)
>>> lst [4, 3, 2, 1, 5]
我创建了一个函数,它可以工作,但我不确定它是否到位。 这是我的代码:
def reverse_sublist(lst,start,end):
sublist=lst[start:end]
sublist.reverse()
lst[start:end]=sublist
print(lst)
【问题讨论】:
您可以使用id()
检查它是否就位。
不,这实际上不是就地的,因为我们必须创建一个临时列表 (sublist
)
“就地”是模棱两可的。这可能意味着“改变输入对象”。这可能意味着“使用O(1)
额外的内存”。后者通常被称为“就地算法”,而前者通常被称为“就地反转列表”,所以你的作业的确切措辞可能会提供线索。
【参考方案1】:
...我不确定它是否到位。
...
lst[start:end]=sublist
是的,它已经到位。 lst
永远不会反弹,只是它的对象发生了变异。
【讨论】:
就是说,呃,不要就地修改东西:(【参考方案2】:只需使用切片:
>>> lst = [1, 2, 3, 4, 5]
>>> lst[0:len(lst[3::-1])]=lst[3::-1]
>>> lst
[4, 3, 2, 1, 5]
或者,也许更容易理解:
>>> lst = [1, 2, 3, 4, 5]
>>> sl=lst[3::-1]
>>> lst[0:len(sl)]=sl
>>> lst
[4, 3, 2, 1, 5]
【讨论】:
这不是 OP 想要的——你正在破坏索引。你想做start = 0
end = 3
lst[start:end] = lst[end-1::-1] if start==0 else lst[end-1:start-1:-1]
,坦率地说,为了可读性,它应该被重写为OP一开始发布的函数!
以负步幅进行切片很棘手。
@adsmith 缺乏早晨咖啡和按钮触发手指之间的不匹配。固定的。正如 Ignacio Vazquez-Abrams 所说,在以负步幅进行切片时,您必须考虑一下。手指帮助。一旦你建立了正确的关系——效果很好。【参考方案3】:
没有临时列表的部分反转(如果您使用 Python 2,请将 range
替换为 xrange
):
def partial_reverse(list_, from_, to):
for i in range(0, int((to - from_)/2)):
(list_[from_+i], list_[to-i]) = (list_[to-i], list_[from_+i])
list_ = [1, 2, 3, 4, 5, 6, 7, 8]
partial_reverse(list_, 3, 7)
print(list_)
【讨论】:
如果您尝试偶数长度,则会出错。例如。 partial_reverse(list_, 2, 7)==[1, 2, 8, 7, 5, 6, 4, 3]【参考方案4】:def reverse_sublist(lst,start,end):
lst[start:end] = lst[start:end][::-1]
return lst
【讨论】:
在这种情况下,即使是最***的切片符号爱好者也可以屈尊使用reversed
吗? ;-)
我认为这需要lst[start:end+1]=lst[start:end+1][::-1]
,否则,正确的解决方案。 +1
@flakes 这会消耗内存 O(k) 吗? k=子字符串的长度。还是一一交换 O(1)?
这不是就地反转,它会在切片创建一个新列表时使用额外的内存。【参考方案5】:
lst[::-1]
是 Python 中反转列表的惯用方式,以下显示了它是如何以及它是就地的:
>>> lst = [1, 2, 3, 4, 5]
>>> id(lst)
12229328
>>> lst[:] = lst[::-1]
>>> lst
[5, 4, 3, 2, 1]
>>> id(lst)
12229328
【讨论】:
【参考方案6】:试试crazy slicing
,见Explain Python's slice notation和http://docs.python.org/2.3/whatsnew/section-slices.html
x = [1,2,3,4,5,6,7,8]
def sublist_reverse(start_rev, end_rev, lst):
return lst[:end_rev-1:start_rev-1]+lst[:[end_rev]
print sublist_reverse(0,4,x)
[出]:
[8, 7, 6, 5, 4, 3, 2, 1]
【讨论】:
【参考方案7】:我有两种in-place 反转的方法,简单的方法是中途循环列表,将元素与相应的mirror-elements 交换。 mirror-element 我的意思是 (first, last), (2nd, 2nd-last), (3rd, 3rd-last) 等等。
def reverse_list(A):
for i in range(len(A) // 2): # half-way
A[i], A[len(A) - i - 1] = A[len(A) - i - 1], A[i] #swap
return A
另一种方式与上述类似,但使用递归而不是“循环”:
def reverse_list(A):
def rev(A, start, stop):
A[start], A[stop] = A[stop], A[start] # swap
if stop - start > 1: # until halfway
rev(A, start + 1, stop - 1)
return A
return rev(A, 0, len(A) - 1)
【讨论】:
【参考方案8】:以部分或完整方式反转列表的最简单方法。
listVar = ['a','b','c','d']
def listReverse(list,start,end):
while(start<end):
temp = list[start]
list[start] = list[end] #Swaping
list[end]=temp
start+=1
end-=1
print(list)
listReverse(listVar,1,3)
输出:- ['a', 'd', 'c', 'b']
【讨论】:
请注意,不需要临时变量,只需使用 oneliner:list[start], list[end] = list[end], list[start]
【参考方案9】:
lst = [1,2,3,4,5,6,7,8]
假设您必须将第 2 个位置反转为第 4 个位置。
lst[2:5] = lst[2:5][::-1]
输出:
[1,2,5,4,3,6,7,8]
【讨论】:
请解释您的代码行,以便其他用户了解其功能。谢谢!【参考方案10】:不确定您是否有与我类似的问题,但我需要在适当的位置反转一个列表。
我唯一缺少的是[:]
exStr = "String"
def change(var):
var[:] = var[::-1] # This line here
print(exStr) #"String"
change(exStr)
print(exStr) #"gnirtS"
【讨论】:
【参考方案11】:我进行了一个小实验,似乎对列表切片的任何分配都会导致内存分配:
import resource
resource.setrlimit(resource.RLIMIT_AS, (64 * 1024, 64 * 1024))
try:
# Python 2
zrange = xrange
arr_size = 3 * 1024
except NameError:
# Python 3
zrange = range
arr_size = 4 * 1024
arr = list(zrange(arr_size))
# We could allocate additional 100 integers, so there should be enough free memory
# to allocate a couple of variables for indexes in the statement below
# additional_memory = list(zrange(100))
# MemoryError is raised here
arr[:] = zrange(arr_size)
所以你必须使用 for 循环来反转子列表。
PS:如果你想重复这个测试,你应该确保 setrlimit RLIMIT_AS 在你的平台上工作正常。此外,arr_size 可能会因不同的 python 实现而有所不同。
【讨论】:
【参考方案12】:就地和常量内存两种方法:
def reverse_swap(arr, start=None, end=None):
"""
Swap two edge pointers until meeting in the center.
"""
if start is None:
start = 0
if end is None:
end = len(arr)
i = start
j = end - 1
while i < j:
arr[i], arr[j] = arr[j], arr[i]
i += 1
j -= 1
def reverse_slice(arr, start=None, end=None):
"""
Use python slice assignment but use a generator on the right-hand-side
instead of slice notation to prevent allocating another list.
"""
if start is None:
start = 0
if end is None:
end = len(arr)
arr[start:end] = (arr[i] for i in range(end - 1, start - 1, -1))
【讨论】:
【参考方案13】:最简单的方法大概是使用切片赋值和reversed()
:
lst[start:end] = reversed(lst[start:end])
您也可以同时切片和反转,但这通常需要使用负索引或特殊处理start = 0
时的情况,即:
lst[start:end] = lst[end-len(lst)-1:start-len(lst)-1:-1]
或
lst[start:end] = lst[end-1::-1] if start == 0 else lst[end-1:start-1:-1]
OTOH,单独使用切片比reversed()
解决方案更快。
【讨论】:
【参考方案14】:更简洁的方式来做到这一点
a = [1,2,3,4,5,6,7,8,9]
i = 2
j = 7
while (i<j):
a[i],a[j]=a[j],a[i]
j -= 1
i += 1
print(a)
【讨论】:
以上是关于如何在适当的位置反转列表中的子列表?的主要内容,如果未能解决你的问题,请参考以下文章