“‘生成器’对象不可下标”错误

为什么在尝试解决 ProjectEuler 问题11时,我的代码第5行出现了这个错误?

for x in matrix:
p = 0
for y in x:
if p < 17:
currentProduct = int(y) * int(x[p + 1]) * int(x[p + 2]) * int(x[p + 3])
if currentProduct > highestProduct:
print(currentProduct)
highestProduct = currentProduct
else:
break
p += 1
'generator' object is not subscriptable
125570 次浏览

您的 x值是一个生成器对象,它是一个 Iterator: 它按顺序生成值,因为它们是由 for循环或通过调用 next(x)请求的。

您试图像访问列表或其他 Sequence类型一样访问它,这使您可以通过索引 x[p + 1]访问任意元素。

如果想通过索引从生成器的输出中查找值,可能需要将其转换为一个列表:

x = list(x)

这解决了您的问题,并且在大多数情况下都适用。但是,这需要一次生成和保存所有的值,所以如果处理的值列表非常长或无限长,或者值非常大,那么它可能会失败。

如果您只需要生成器中的一个值,那么您可以使用 itertools.islice(x, p)来丢弃第一个 p值,然后使用 next(...)来获取您需要的值。这样就不需要在内存中保存多个项或计算超出所需的值。

import itertools


result = next(itertools.islice(x, p))

作为 Jeremy 答案的一个扩展,我想谈谈关于代码设计的一些想法:

看看您的算法,似乎您实际上并不需要对生成器产生的值进行真正的随机访问: 在任何时候,您只需要保持四个连续的值(三个,再加上一点额外的优化)。这在您的代码中有点模糊,因为您混合了索引和迭代: 如果索引可以工作(当然它不能) ,那么您的 y可以写成 x[p + 0]

对于这样的算法,你可以应用一种“滑动窗口”技术,如下面的代码精简版本所示:

import itertools, functools, operator
vs = [int(v) for v in itertools.islice(x, 3)]
for v in x:
vs.append(int(v))
currentProduct = functools.reduce(operator.mul, vs, 1)
print(currentProduct)
vs = vs[1:]