ChatGPT解决这个技术问题 Extra ChatGPT

如何反转列表?

如何在 Python 中反向迭代列表?

array = [0, 10, 20, 40]
for (i = array.length() - 1; i >= 0; i--)

M
Mateen Ulhaq

使用 reversed 函数:

>>> xs = [0, 10, 20, 40]
>>> for i in reversed(xs):
...     print(i)

要获得反向列表:

>>> list(reversed(xs))
[40, 20, 10, 0]

你不能只使用:array[::-1] 吗?
@kdlannoy 根据答案中链接到的页面,“与扩展切片相比,例如 range(1,4)[::-1], reversed() 更容易阅读,运行速度更快,并且使用的内存大大减少。 "
当我测试这个切片时,它的速度大约是原来的两倍(当反转一个 10k 元素列表并从中创建一个列表时)。我没有测试内存消耗。但是,如果您之后不需要强制转换为列表,reverse 可能会更快。
值得注意的是,这与 reverse([1,2,3]), nb the 'd' at the end ...这是下面的其他答案之一,它就地执行此操作,而返回一个迭代器。
为什么使用 reversed() 而不是切片?阅读 Python 之禅,第 7 条规则:可读性很重要!
M
Mateen Ulhaq
>>> xs = [0, 10, 20, 40]
>>> xs[::-1]
[40, 20, 10, 0]

here 解释了扩展切片语法。另见,documentation


它适用于任何可交互的,而不仅仅是列表。缺点是没有到位。
@Tim 它返回一个切片,因此不会更改实际列表内容
@Swiss 并非在每个可迭代中,例如 set 都是可迭代的,但不可下标。
@lunixbochs reversed 返回一个迭代器,而不是 Python 3 中的列表。
这完全符合 OP 的要求,但它非常 hacky,在某种程度上你必须完全使用 L[::-1] 并且它不会为 start, stop 取值,因为 slice 方法是用定义的。尝试使用 L[4:0:-1],您会发现问题。
g
ghostdog74
>>> L = [0,10,20,40]
>>> L.reverse()
>>> L
[40, 20, 10, 0]

或者

>>> L[::-1]
[40, 20, 10, 0]

[start:stop:step] 所以 step 是 -1
详细信息:第一个就地修改列表,第二个只返回一个新的反向列表,但不修改原始列表。
第二个示例应该是 L=L[::-1] 以实际反转列表,否则您只会反向返回值
假设我有 l= [1,2,3,4,5,6] 并且 n=2 他们的结果必须是 [6,5,1,2,3,4],我们该怎么做
你可以这样做:b = l[-n:] b.reverse() l = b + l[:len(l) - n]
L
LightCC

带有解释和时序结果的方法总结

有三种不同的内置方法可以反转列表。哪种方法最好取决于您是否需要:

就地反转现有列表(更改原始列表变量) 最佳解决方案是 object.reverse() 方法 创建反转列表的迭代器(因为您要将其提供给 for 循环、生成器等)最佳解决方案是 reversed(object) 创建迭代器 创建列表的副本,只是以相反的顺序(以保留原始列表) 最佳解决方案是使用具有 -1 步长的切片:object[::-1]

从速度的角度来看,最好使用上面的内置函数来反转一个列表。对于反转,与手动创建的循环或生成器相比,它们在短列表(10 项)上快 2 到 8 倍,在长列表上快 300+ 倍。这是有道理的——它们是用母语(即C)编写的,由专家创建、审查和优化。它们也不太容易出现缺陷,更有可能处理边缘和角落的情况。

测试脚本

将这个答案中的所有代码片段放在一起,制作一个脚本,该脚本将运行下面描述的反转列表的不同方式。它将在运行 100,000 次时为每个方法计时。对于长度为 2、10 和 1000 个项目的列表,结果显示在最后一节中。

from timeit import timeit
from copy import copy

def time_str_ms(t):
    return '{0:8.2f} ms'.format(t * 1000)

方法一:使用 obj.reverse() 原地反转

如果目标只是颠倒现有列表中项目的顺序,而不是循环它们或获取要使用的副本,请使用 <list>.reverse() 函数。直接在列表对象上运行它,所有项目的顺序将被颠倒:

请注意,以下将反转给定的原始变量,即使它也返回反转的列表。即您可以使用此函数输出创建副本。通常,您不会为此创建函数,但计时脚本需要它。

我们测试这两种方式的性能 - 首先只是原地反转列表(更改原始列表),然后复制列表并在之后反转它,看看与其他方法相比,这是否是创建反向副本的最快方法方法。

def rev_in_place(mylist):
    mylist.reverse()
    return mylist

def rev_copy_reverse(mylist):
    a = copy(mylist)
    a.reverse()
    return a

方法 2:使用切片 obj[::-1] 反转列表

内置的索引切片方法允许您复制任何索引对象的一部分。

它不影响原始对象

它构建一个完整的列表,而不是一个迭代器

通用语法是:<object>[first_index:last_index:step]。要利用切片创建一个简单的反向列表,请使用:<list>[::-1]。将选项留空时,它将它们设置为对象的第一个和最后一个元素的默认值(如果步长为负值,则反转)。

索引允许使用负数,它从对象索引的末尾向后计数(即-2 是倒数第二个项目)。当步长为负时,它将从最后一项开始,并按该数量向后索引。

def rev_slice(mylist):
    a = mylist[::-1]
    return a

方法 3:使用 reversed(obj) 迭代器函数反转列表

有一个 reversed(indexed_object) 函数:

这会创建一个反向索引迭代器,而不是一个列表。如果您将它提供给循环以在大型列表中获得更好的性能,那就太好了

这会创建一个副本并且不会影响原始对象

使用原始迭代器进行测试,并从迭代器创建列表。

def reversed_iterator(mylist):
    a = reversed(mylist)
    return a

def reversed_with_list(mylist):
    a = list(reversed(mylist))
    return a

方法 4:使用自定义/手动索引的反向列表

正如时间所示,创建自己的索引方法是一个坏主意。除非您确实需要做一些自定义的事情,否则请使用内置方法。这仅仅意味着学习内置方法。

也就是说,较小的列表大小并没有很大的惩罚,但是当你扩大惩罚时,惩罚就会变得巨大。我敢肯定,下面的代码可以优化,但它永远无法匹配内置方法,因为它们是直接用本地语言实现的。

def rev_manual_pos_gen(mylist):
    max_index = len(mylist) - 1
    return [ mylist[max_index - index] for index in range(len(mylist)) ]

def rev_manual_neg_gen(mylist):
    ## index is 0 to 9, but we need -1 to -10
    return [ mylist[-index-1] for index in range(len(mylist)) ]

def rev_manual_index_loop(mylist):
    a = []
    reverse_index = len(mylist) - 1
    for index in range(len(mylist)):
        a.append(mylist[reverse_index - index])
    return a
    
def rev_manual_loop(mylist):
    a = []
    reverse_index = len(mylist)
    for index, _ in enumerate(mylist):
        reverse_index -= 1
        a.append(mylist[reverse_index])
    return a

计时每种方法

以下是脚本的其余部分,用于计时每种反转方法。它显示使用 obj.reverse() 就地反转和创建 reversed(obj) 迭代器总是最快的,而使用切片是创建副本的最快方法。

这也证明了除非你必须这样做,否则不要试图自己创造一种方法!

loops_to_test = 100000
number_of_items = 10
list_to_reverse = list(range(number_of_items))
if number_of_items < 15:
    print("a: {}".format(list_to_reverse))
print('Loops: {:,}'.format(loops_to_test))
# List of the functions we want to test with the timer, in print order
fcns = [rev_in_place, reversed_iterator, rev_slice, rev_copy_reverse,
        reversed_with_list, rev_manual_pos_gen, rev_manual_neg_gen,
        rev_manual_index_loop, rev_manual_loop]
max_name_string = max([ len(fcn.__name__) for fcn in fcns ])
for fcn in fcns:
    a = copy(list_to_reverse) # copy to start fresh each loop
    out_str = ' | out = {}'.format(fcn(a)) if number_of_items < 15 else ''
    # Time in ms for the given # of loops on this fcn
    time_str = time_str_ms(timeit(lambda: fcn(a), number=loops_to_test))
    # Get the output string for this function
    fcn_str = '{}(a):'.format(fcn.__name__)
    # Add the correct string length to accommodate the maximum fcn name
    format_str = '{{fx:{}s}} {{time}}{{rev}}'.format(max_name_string + 4)
    print(format_str.format(fx=fcn_str, time=time_str, rev=out_str))

计时结果

结果表明,缩放最适用于最适合特定类型反转的内置方法。换句话说,随着对象元素数量的增加,内置方法比其他方法更快。

直接实现你需要的内置方法比把东西串起来更好。即如果您需要反向列表的副本,最好进行切片 - 它比从 list(reversed(obj)) 函数创建重复列表更快,并且比制作列表副本然后执行就地 obj.reverse() 更快,但绝不会速度提高一倍以上。同时 - 对于大型列表,自定义方法可能需要更长的数量级。

对于缩放,对于 1000 项列表,reversed(<list>) 函数调用需要约 30 毫秒来设置迭代器,就地反转只需约 55 毫秒,使用 slice 方法需要约 210 毫秒来创建完整反转的副本列表,但我做的最快的手动方法花了 ~8400 毫秒

列表中有 2 项:

a: [0, 1]
Loops: 100,000
rev_in_place(a):             24.70 ms | out = [1, 0]
reversed_iterator(a):        30.48 ms | out = <list_reverseiterator object at 0x0000020242580408>
rev_slice(a):                31.65 ms | out = [1, 0]
rev_copy_reverse(a):         63.42 ms | out = [1, 0]
reversed_with_list(a):       48.65 ms | out = [1, 0]
rev_manual_pos_gen(a):       98.94 ms | out = [1, 0]
rev_manual_neg_gen(a):       88.11 ms | out = [1, 0]
rev_manual_index_loop(a):    87.23 ms | out = [1, 0]
rev_manual_loop(a):          79.24 ms | out = [1, 0]

列表中有 10 项:

rev_in_place(a):             23.39 ms | out = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
reversed_iterator(a):        30.23 ms | out = <list_reverseiterator object at 0x00000290A3CB0388>
rev_slice(a):                36.01 ms | out = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
rev_copy_reverse(a):         64.67 ms | out = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
reversed_with_list(a):       50.77 ms | out = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
rev_manual_pos_gen(a):      162.83 ms | out = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
rev_manual_neg_gen(a):      167.43 ms | out = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
rev_manual_index_loop(a):   152.04 ms | out = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
rev_manual_loop(a):         183.01 ms | out = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0]

列表中有 1000 个项目:

rev_in_place(a):             56.37 ms
reversed_iterator(a):        30.47 ms
rev_slice(a):               211.42 ms
rev_copy_reverse(a):        295.74 ms
reversed_with_list(a):      418.45 ms
rev_manual_pos_gen(a):     8410.01 ms
rev_manual_neg_gen(a):    11054.84 ms
rev_manual_index_loop(a): 10543.11 ms
rev_manual_loop(a):       15472.66 ms

f
fahad

要反转相同的列表,请使用:

array.reverse()

要将反向列表分配到其他列表中,请使用:

newArray = array[::-1] 

S
SimonM

使用切片,例如 array = array[::-1],是一个巧妙的技巧并且非常 Pythonic,但对于新手来说可能有点晦涩难懂。使用 reverse() 方法是进行日常编码的好方法,因为它易于阅读。

但是,如果您需要在面试问题中反转列表,您可能无法使用这些内置方法。面试官将看你如何解决问题,而不是 Python 知识的深度,需要一种算法方法。以下示例使用经典交换可能是一种方法:-

def reverse_in_place(lst):      # Declare a function
    size = len(lst)             # Get the length of the sequence
    hiindex = size - 1
    its = size/2                # Number of iterations required
    for i in xrange(0, its):    # i is the low index pointer
        temp = lst[hiindex]     # Perform a classic swap
        lst[hiindex] = lst[i]
        lst[i] = temp
        hiindex -= 1            # Decrement the high index pointer
    print "Done!"

# Now test it!!
array = [2, 5, 8, 9, 12, 19, 25, 27, 32, 60, 65, 1, 7, 24, 124, 654]

print array                    # Print the original sequence
reverse_in_place(array)        # Call the function passing the list
print array                    # Print reversed list


**The result:**
[2, 5, 8, 9, 12, 19, 25, 27, 32, 60, 65, 1, 7, 24, 124, 654]
Done!
[654, 124, 24, 7, 1, 65, 60, 32, 27, 25, 19, 12, 9, 8, 5, 2]

请注意,这不适用于元组或字符串序列,因为字符串和元组是不可变的,即您不能写入它们来更改元素。


经典交换可以通过 lst[hiindex], lst[i] = lst[i], lst[hiindex] 完成,我认为... ;-)
@Samoth 语法不是很清楚,行为也不是很明显。不同的步骤更有意义。
为什么人们说像 array[::-1] 这样的东西是 pythonic 的? python zen 告诉我们,显式优于隐式,而且可读性很重要。像这样的东西根本不明确和可读。
@k4ppa:如果您了解 Pythonarray[::-1] 非常可读且非常明确。 “可读”并不意味着“以前从未使用过 Python 切片的人必须能够阅读它”; [::-1] 反转切片在 Python 中是一个非常常见的习语(你会一直在现有代码中遇到它),并且如果你经常使用 Python,它是完全可读的。当然,first10 = []for i in range(10): first10.append(array[i]) 清晰明确,但这并不比 first10 = array[:10] 更好。
为什么迭代次数大小/2?其背后的逻辑是什么?另外,如果它的长度不是偶数怎么办。那么它会是 ceil(size/2)
C
Chris_Rands

我发现(与其他一些建议相反)l.reverse() 是迄今为止在 Python 3 和 2 中反转长列表的最快方法。我很想知道其他人是否可以复制这些时间。

l[::-1] 可能较慢,因为它会在反转列表之前复制列表。在 reversed(l) 进行的迭代器周围添加 list() 调用必须增加一些开销。当然,如果您想要列表的副本或迭代器,请使用这些相应的方法,但如果您只想反转列表,那么 l.reverse() 似乎是最快的方法。

功能

def rev_list1(l):
    return l[::-1]

def rev_list2(l):
    return list(reversed(l))

def rev_list3(l):
    l.reverse()
    return l

列表

l = list(range(1000000))

Python 3.5 计时

timeit(lambda: rev_list1(l), number=1000)
# 6.48
timeit(lambda: rev_list2(l), number=1000)
# 7.13
timeit(lambda: rev_list3(l), number=1000)
# 0.44

Python 2.7 计时

timeit(lambda: rev_list1(l), number=1000)
# 6.76
timeit(lambda: rev_list2(l), number=1000)
# 9.18
timeit(lambda: rev_list3(l), number=1000)
# 0.46

list.reverse 是最快的,因为它会原地反转
您是对的,list.reverse() 最快,但您正在惩罚 reversed(最好在您想要新的 list 时使用,只是为了迭代现有的 list在不改变原始的情况下以相反的顺序排列)和切片(这也避免了改变原始 list,并且当输入较小时通常比 reversed 快)。是的,如果您不需要副本,那么复制的任何东西都更昂贵,但很多时候,您不想改变原始值。
即使如此,它看起来也像 reversed still loses to list.reverse(),但考虑到它不会改变输入 list,它在许多情况下会更好。 reversed 的损失很小(比 list.reverse() 长约 1/6)。
S
Swiss
for x in array[::-1]:
    do stuff

这种切片方法的可读性不是很高。 Pythonic 方法是使用 reverse() 方法。 ;-)
@SimonM reverse() 一目了然肯定更容易理解。
E
Eyal Levin

使用 reversedlist

>>> list1 = [1,2,3]
>>> reversed_list = list(reversed(list1))
>>> reversed_list
>>> [3, 2, 1]

n
nonopolarity
array=[0,10,20,40]
for e in reversed(array):
  print e

g
gpj

使用 reversed(array) 可能是最好的路线。

>>> array = [1,2,3,4]
>>> for item in reversed(array):
>>>     print item

您是否需要了解如何在不使用内置 reversed 的情况下实现这一点。

def reverse(a):
    midpoint = len(a)/2
    for item in a[:midpoint]:
        otherside = (len(a) - a.index(item)) - 1
        temp = a[otherside]
        a[otherside] = a[a.index(item)]
        a[a.index(item)] = temp
    return a

这应该花费 O(N) 时间。


正在寻找如何在不使用反向功能的情况下做到这一点。谢谢。
或使用 list = list.reverse() 原地反转
列表 a 是按值传递还是按引用传递?它是通过尊敬传递的,所以你不需要 return a。您已在 a 的原始内存位置进行了修改
H
H6.

另一种解决方案是为此使用 numpy.flip

import numpy as np
array = [0, 10, 20, 40]
list(np.flip(array))
[40, 20, 10, 0]

很棒,很难忘。与其他解决方案不同(对于这种非通用测试用例的 OP 感到羞耻),它甚至适用于未排序的列表(随机数等)。
T
Temak

如果要将反向列表的元素存储在其他变量中,则可以使用 revArray = array[::-1]revArray = list(reversed(array))

但是第一个变体稍微快一点:

z = range(1000000)
startTimeTic = time.time()
y = z[::-1]
print("Time: %s s" % (time.time() - startTimeTic))

f = range(1000000)
startTimeTic = time.time()
g = list(reversed(f))
print("Time: %s s" % (time.time() - startTimeTic))

输出:

Time: 0.00489711761475 s
Time: 0.00609302520752 s

下一次,您可能想要使用 timeit
这是一个糟糕的测试,有两个原因。首先,您只测试一次迭代 - 只需几毫秒即可执行 - 这意味着结果可能是侥幸。其次,根据您使用的是 Python 2 还是 Python 3,range(1000000) 可能根本不是一个列表,而是一个 range 对象,它有自己的 __reversed__ 方法,其行为可能与 list 的方法不同.
1
101

您还可以使用数组索引的 bitwise complement 反向遍历数组:

>>> array = [0, 10, 20, 40]
>>> [array[~i] for i, _ in enumerate(array)]
[40, 20, 10, 0]

无论你做什么,都不要这样做;)


H
Heezes

使用一些逻辑

使用一些老派的逻辑来练习面试。

前后交换数字。使用两个指针 index[0] 和 index[last]

def reverse(array):
    n = array
    first = 0
    last = len(array) - 1
    while first < last:
      holder = n[first]
      n[first] = n[last]
      n[last] = holder
      first += 1
      last -= 1
    return n

input -> [-1 ,1, 2, 3, 4, 5, 6]
output -> [6, 5, 4, 3, 2, 1, -1]

如果我们将列表一分为二并将第一个与最后一个索引交换,那么时间复杂度将比列出的样本更有效。
P
Peter Mortensen

使用列表理解:

[array[n] for n in range(len(array)-1, -1, -1)]

M
Marcelo Guedes

组织价值观:

在 Python 中,列表的顺序也可以通过排序来操作,按数字/字母顺序组织变量:暂时:

打印(排序(my_list))

永恒的:

my_list.sort(), print(my_list)

您可以使用标志“reverse=True”进行排序:

print(sorted(my_list, reverse=True))

or

my_list.sort(reverse=True), print(my_list)

没有组织

也许您不想对值进行排序,而只想反转值。然后我们可以这样做:

print(list(reversed(my_list)))

**在列出顺序中,数字优先于字母。 Python 价值观的组织很棒。

编辑1:一位错误的版主声称我的答案是副本并删除了我的旧帖子。


F
Fed

使用最少的内置功能,假设它是面试设置

array = [1, 2, 3, 4, 5, 6,7, 8]
inverse = [] #create container for inverse array
length = len(array)  #to iterate later, returns 8 
counter = length - 1  #because the 8th element is on position 7 (as python starts from 0)

for i in range(length): 
   inverse.append(array[counter])
   counter -= 1
print(inverse)

A
Anuj Gupta

有 3 种方法可以获取反向列表:

切片方法一:reversed_array = array[-1::-1] 切片方法二:reversed_array2 = array[::-1] 使用内置函数:reversed_array = array.reverse()

第三个函数实际上反转了列表对象。这意味着不会保留原始数据的副本。如果您不想维护旧版本,这是一个很好的方法。但是,如果您确实想要原始和反向版本,这似乎不是一个解决方案。


r
rjmoggach

问题不是如何反向返回列表,而是如何使用示例列表名称 array 反向列表。

要反转名为 "array" 的列表,请使用 array.reverse()

所描述的非常有用的切片方法也可用于通过使用 array[:] = array[::-1] 将列表定义为自身的切片修改来反转列表。


最后一句不正确,这并没有将列表颠倒到位;它应该说 array[:] = array[::-1]
J
John Machin

将您的要求最直接地转换为 Python 的方法是以下 for 语句:

for i in xrange(len(array) - 1, -1, -1):
   print i, array[i]

这相当神秘,但可能很有用。


D
David Guyon
def reverse(my_list):
  L = len(my_list)
  for i in range(L/2):
    my_list[i], my_list[L-i - 1] = my_list[L-i-1], my_list[i]
  return my_list

// 楼层除法运算符更好。
S
Shawn Tsai
def reverse(text):
    output = []
    for i in range(len(text)-1, -1, -1):
        output.append(text[i])
    return output

R
Rick

您总是可以将列表视为堆栈,只是从列表的后端将元素从堆栈顶部弹出。这样,您就可以利用堆栈的先进后出特性。当然,您正在使用第一个数组。我确实喜欢这种方法,因为它非常直观,您可以看到一个列表是从后端消耗的,而另一个列表是从前端构建的。

>>> l = [1,2,3,4,5,6]; nl=[]
>>> while l:
        nl.append(l.pop())  
>>> print nl
[6, 5, 4, 3, 2, 1]

R
Rohan Chavan
list_data = [1,2,3,4,5]
l = len(list_data)
i=l+1
rev_data = []
while l>0:
  j=i-l
  l-=1
  rev_data.append(list_data[-j])
print "After Rev:- %s" %rev_data 

g
grf
>>> l = [1, 2, 3, 4, 5]
>>> print(reduce(lambda acc, x: [x] + acc, l, []))
[5, 4, 3, 2, 1]

此解决方案比 l[::-1] 慢约 4.5k 倍,同时可读性要差得多。遗憾的是,Python 中的函数式编程相当慢。
J
Julien

通过切换相反索引的引用来就地反转:

>>> l = [1,2,3,4,5,6,7]    
>>> for i in range(len(l)//2):
...     l[i], l[-1-i] = l[-1-i], l[i]
...
>>> l
[7, 6, 5, 4, 3, 2, 1]

适用于奇数长度的列表!
我的解决方案是对的!你知道python是如何实现索引的。从右到左你有 0,1,2... 从左到右你有 -1,-2,-3.. 等等。要反转一个列表,你把它分成两部分,然后将索引相乘右边由他们的对立面在左边减一。
S
SuperNova

可以使用 __reverse__ 来完成,它返回一个生成器。

>>> l = [1,2,3,4,5]
>>> for i in l.__reversed__():
...   print i
... 
5
4
3
2
1
>>>

P
Palash Mondal

在一行代码中反转用户输入值:

for i in input()[::-1]: print(i,end='')

C
Corman

这是一种使用生成器懒惰地评估反向的方法:

def reverse(seq):
    for x in range(len(seq), -1, -1): #Iterate through a sequence starting from -1 and increasing by -1.
        yield seq[x] #Yield a value to the generator

现在像这样迭代:

for x in reverse([1, 2, 3]):
    print(x)

如果您需要清单:

l = list(reverse([1, 2, 3]))