在Python中倒序循环并获取索引

3

在Python中有多种循环的方式。例如,我们可以使用以下方法:

arr=[5,6,8]
for i in range(len(arr)-1, -1, -1):
  print(i," ",arr[i])

这提供了

2   8
1   6
0   5

我可以用那个解决我需要的问题,但我很好奇。还有一种循环回路的方式是

for im in arr[::-1]:
  print(im) 

看起来很不错,对吧? 这提供了

8
6
5

我的问题是,使用这种第二种方法,是否有一种方法可以获得元素以及索引(2,1,0)?

这个回答解决了你的问题吗?在'for'循环中访问索引? - mkrieger1
考虑使用 enumerate 函数,以获得(索引和数字)的元组对。 - Daniel Hao
1
如果你只需要索引,类似于 range(len(arr)-1, -1, -1),你也可以使用 reversed(range(len(arr))),这可能更直观和易读。 - tobias_k
7个回答

3

使用内置方法 reversed

arr = [5, 6, 8]
for i in reversed(range(0,len(arr))):
    print(i,arr[i])

虽然在Python中使用列表索引并不是很符合Pythonic的风格,但这个问题可能是一个“保持简单”的情况。我喜欢这个解决方案的简洁性。 - joanis

2

有一个内置函数可以实现这个功能:reversed。使用负数步长的rangeslice可能会更难理解和阅读,所以这种方法可能更加直观易懂。

如果只需要索引,可以直接将range传递给reversed函数:

arr = list("ABC")

for i in reversed(range(len(arr))):
    print(i, arr[i])                   
# 2 C
# 1 B
# 0 A

对于索引和元素,您必须在反转之前将enumerate迭代器收集到一个list中:

for i, x in reversed(list(enumerate(arr))):
    print(i, x)                
# 2 C
# 1 B
# 0 A

等等,我不明白为什么需要使用列表,如果第一段代码已经能够工作。 - KansaiRobot
@KansaiRobot enumerate 返回一个通用的迭代器/生成器,不能直接反转。range 是一个特殊的范围迭代器,可以直接反转,因为它的长度是先验已知的。在 enumerate(arr) 的情况下,实际上你也知道长度,但你也可以从例如 zipfilter 或任何其他类型的生成器/迭代器创建一个 enumerate,那么就不可能了,所以一般情况下 enumerate 也不能被反转,因为在生成所有其他元素之前,你不知道长度或者实际上的最后一个元素。 - tobias_k

2
这里有一种使用reversed()zip()的方法,它应该具有内存效率:


arr = [5, 6, 8]

for idx, elem in zip(reversed(range(len(arr))),
                     reversed(arr)
                     ):
    print(idx, elem)

输出:

2 8
1 6
0 5

ж•өжөЃпәЊдҢ†еЏҒжњ‰ењЁarrеҚ з”Ёдғ†дҢ зљ„дёЂеҚЉз©ғй—ІRAMж—¶ж‰Қз›ёе…ігЂ‚ - tobias_k

1
for idx, elem in list(enumerate(arr))[::-1]:
    print(idx, elem)

这里使用enumerate来保持元素与其特定索引的对应关系。然后我们将其转换为列表并进行反转(不进行转换无法反转enumerate结果)。无需手动跟踪任何顺序(如减法)。

您也可以直接反转正向范围:

for idx in range(len(arr))[::-1]:
   print(idx, arr[idx])

Python实际上以一种聪明的方式反转范围,而无需将其转换为列表,因此即使对于大型数据也可以正常工作:

>>> range(10)[::-1]
range(9, -1, -1)

这意味着 range(len(arr))[::-1] 将以与您的 range(len(arr)-1, -1, -1) 完全相同的方式,以完全相同的速度工作,同时看起来更好!

@mozway 在不预先知道序列长度的情况下,无法反向枚举序列。 - Kaihaku
@h4z3 这是一种更好的方法 ;) - mozway
在内存中创建一个全新的列表仅用于迭代是非常糟糕的。 - salt-die
@salt-die 在你发表评论之前的10分钟内,我已经添加了一种全新的生成器方法到我的答案中,我公开表示这种方法与OP原始方法的效果相同,但看起来更好。 - h4z3
实际上,还有另一个用户在我之后发布了与我完全相同的两种方法,只是顺序不同。而且这都在你的评论之前。但是评论中却批评了我并给了我一个负评。 - h4z3
显示剩余2条评论

0
i = len(arr) - 1
for im in arr[::-1]:
    print(i, " ", im)
    i -= 1

-1

您可以使用enumerate并从初始长度中减去:

arr=[5,6,8]
for i,im in enumerate(arr[::-1]):
    print(len(arr)-i-1, im)

输出:

2 8
1 6
0 5

2
也许是因为手动减去索引会变得不必要地复杂和容易出错。 - mkrieger1

-1

使用索引进行迭代的常规方法是使用enumerate。可以通过从序列长度中减去索引来反向索引:

In [51]: arr = [5, 6, 8]
    ...: for i, n in enumerate(arr):
    ...:     print(i, n)
    ...: 
0 5
1 6
2 8

In [52]: for i, n in enumerate(reversed(arr)):
    ...:     print(len(arr) - i - 1, n)
    ...: 
2 8
1 6
0 5

请注意,reversed 不会在内存中创建新的列表,如果只是迭代,它比 [::-1] 更可取。

[::-1]会创建另一个列表吗? - KansaiRobot
1
是的,它会创建一个全新的列表。 - salt-die

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