104

人们经常在关于 SO 的 python 问题中找到这种类型的表达式。要么只访问可迭代的所有项目

for i in range(len(a)):
    print(a[i])

这只是一种笨拙的写作方式:

for e in a:
    print(e)

或分配给可迭代的元素:

for i in range(len(a)):
    a[i] = a[i] * 2

应该与以下内容相同:

for i, e in enumerate(a):
     a[i] = e * 2
# Or if it isn't too expensive to create a new iterable
a = [e * 2 for e in a]

或用于过滤索引:

for i in range(len(a)):
    if i % 2 == 1: continue
    print(a[i])

可以这样表达:

for e in a [::2]:
    print(e)

或者当您只需要列表的长度而不是其内容时:

for _ in range(len(a)):
    doSomethingUnrelatedToA()

这可能是:

for _ in a:
    doSomethingUnrelatedToA()

在 python 中,我们有enumerate、切片、filtersorted等...由于 pythonfor构造旨在迭代可迭代对象,而不仅仅是整数范围,是否存在您需要的实际用例in range(len(a))

4

14 回答 14

18

如果您需要使用序列的索引,那么可以 - 您使用它...例如,相当于numpy.argsort ...:

>>> a = [6, 3, 1, 2, 5, 4]
>>> sorted(range(len(a)), key=a.__getitem__)
[2, 3, 1, 5, 4, 0]
于 2013-10-04T15:13:56.797 回答
11

简短回答:从数学上讲,不,实际上,是的,例如对于意向编程。

从技术上讲,答案是“不,不需要”,因为它可以使用其他构造来表达。但在实践中,我使用for i in range(len(a)(或者for _ in range(len(a))如果我不需要索引)明确表示我想要迭代序列中的项目的次数,而不需要将序列中的项目用于任何事情。

所以:“有需要吗?” ? — 是的,出于可读性目的,我需要它来表达代码的含义/意图。

另见:https ://en.wikipedia.org/wiki/Intentional_programming

显然,如果根本没有与迭代相关联的集合,是for ... in range(len(N))唯一的选择,以免求助于i = 0; while i < N; i += 1 ...

于 2013-10-04T15:03:45.587 回答
11

如果您需要同时访问列表的两个元素怎么办?

for i in range(len(a[0:-1])):
    something_new[i] = a[i] * a[i+1]

您可以使用它,但可能不太清楚:

for i, _ in enumerate(a[0:-1]):
     something_new[i] = a[i] * a[i+1]

就我个人而言,我也不是 100% 满意!

于 2016-03-03T15:16:19.447 回答
2

根据评论和个人经验,我说不,没有必要range(len(a))你能做的所有事情都可以用range(len(a))另一种(通常更有效)的方式来完成。

您在帖子中举了很多例子,所以我不会在这里重复。相反,我将为那些说“如果我只想要 的长度而a不是项目怎么办?”的人举个例子。这是您可能会考虑使用的唯一一次range(len(a))。但是,即使这样也可以这样做:

>>> a = [1, 2, 3, 4]
>>> for _ in a:
...     print True
...
True
True
True
True
>>>

Clements 的答案(如 Allik 所示)也可以修改为删除range(len(a))

>>> a = [6, 3, 1, 2, 5, 4]
>>> sorted(range(len(a)), key=a.__getitem__)
[2, 3, 1, 5, 4, 0]
>>> # Note however that, in this case, range(len(a)) is more efficient.
>>> [x for x, _ in sorted(enumerate(a), key=lambda i: i[1])]
[2, 3, 1, 5, 4, 0]
>>>

所以,总而言之range(len(a))不需要。它唯一的优点是可读性(它的意图很明确)。但这只是偏好和代码风格。

于 2013-10-04T15:14:27.397 回答
2

有时 matplotlib 需要range(len(y)),例如 while y=array([1,2,5,6])plot(y)可以正常工作,scatter(y)但不需要。一个必须写scatter(range(len(y)),y)。(就个人而言,我认为这是scatter;plot和它的朋友中的一个错误scatterstem应该尽可能使用相同的调用序列。)

于 2014-09-11T18:00:40.647 回答
2

当您需要使用索引进行某种操作并且拥有当前元素还不够时,这很好。以存储在数组中的二叉树为例。如果您有一个方法要求您返回包含每个节点的直接子节点的元组列表,那么您需要索引。

#0 -> 1,2 : 1 -> 3,4 : 2 -> 5,6 : 3 -> 7,8 ...
nodes = [0,1,2,3,4,5,6,7,8,9,10]
children = []
for i in range(len(nodes)):
  leftNode = None
  rightNode = None
  if i*2 + 1 < len(nodes):
    leftNode = nodes[i*2 + 1]
  if i*2 + 2 < len(nodes):
    rightNode = nodes[i*2 + 2]
  children.append((leftNode,rightNode))
return children

当然,如果你正在处理的元素是一个对象,你可以调用一个 get children 方法。但是,是的,只有在进行某种操作时才真正需要索引。

于 2015-12-07T22:24:23.547 回答
1

我有一个用例,我不相信您的任何示例都涵盖了。

boxes = [b1, b2, b3]
items = [i1, i2, i3, i4, i5]
for j in range(len(boxes)):
    boxes[j].putitemin(items[j])

虽然很高兴学习一种更优雅的方法,但我对 python 还是比较陌生。

于 2015-04-28T23:15:29.563 回答
1

如果您必须遍历len(a)对象的第一项b(大于a),您可能应该使用range(len(a))

for i in range(len(a)):
    do_something_with(b[i])
于 2016-03-04T18:46:59.330 回答
1

有时,你真的不在乎收藏本身。例如,创建一个简单的模型拟合线以将“近似值”与原始数据进行比较:

fib_raw = [1, 1, 2, 3, 5, 8, 13, 21] # Fibonacci numbers

phi = (1 + sqrt(5)) / 2
phi2 = (1 - sqrt(5)) / 2

def fib_approx(n): return (phi**n - phi2**n) / sqrt(5)

x = range(len(data))
y = [fib_approx(n) for n in x]

# Now plot to compare fib_raw and y
# Compare error, etc

在这种情况下,斐波那契数列本身的值是无关紧要的。我们需要的只是我们要比较的输入序列的大小。

于 2016-12-06T01:38:09.187 回答
0

我的代码是:

s=["9"]*int(input())
for I in range(len(s)):
    while not set(s[I])<=set('01'):s[i]=input(i)
print(bin(sum([int(x,2)for x in s]))[2:])

它是一个二进制加法器,但我认为不能替换范围 len 或内部以使其更小/更好。

于 2018-06-05T12:15:11.033 回答
0

一个有效的情况是,如果您需要使用一个集合的长度来定义另一个集合,例如

collection = [1,2,3,4]

constant_array = [constant_val for _ in range(len(collection))]

# For lists, you can also use:
constant_array2 = [constant_val] * len(collection)
于 2022-02-19T13:24:32.930 回答
0

一个问题for i, num in enumerate(a)num当你改变时它不会改变a[i]。例如,这个循环:

for i, num in enumerate(a):
    while num > 0:
        a[i] -= 1

永远不会结束。当然,您仍然可以在交换 for 的每次使用时使用 enumerate numa[i]但这违背了 enumerate 的全部目的,因此 using for i in range(len(a))just 变得更加合乎逻辑和可读性。

于 2022-01-23T19:37:10.117 回答
0

有人说这for i in range len(a)是给初学者的,但是如果我想同时访问元素和索引怎么办。

于 2021-03-31T06:54:08.240 回答
0

非常简单的例子:

def loadById(self, id):
    if id in range(len(self.itemList)):
        self.load(self.itemList[id])

我想不出一个不快速使用 range-len 组合的解决方案。

但可能相反,我猜应该这样做try .. except以保持pythonic..

于 2015-09-27T18:05:40.100 回答