【发布时间】:2017-06-22 21:22:48
【问题描述】:
通常我们必须 (1) 声明一个列表 (2) 使用 sum() 计算该列表的总和
但现在我想指定一个以 1 开始,间隔为 4 的列表,100 个元素,如下所示:
[1,5,9,13,17,21,25,29,33,37,…]
我不想包含数学公式,所以
(1) 如何在不声明这个列表的情况下得到总和?
(2) 如何快速得到这个列表第101个元素到第200个元素的总和?
【问题讨论】:
通常我们必须 (1) 声明一个列表 (2) 使用 sum() 计算该列表的总和
但现在我想指定一个以 1 开始,间隔为 4 的列表,100 个元素,如下所示:
[1,5,9,13,17,21,25,29,33,37,…]
我不想包含数学公式,所以
(1) 如何在不声明这个列表的情况下得到总和?
(2) 如何快速得到这个列表第101个元素到第200个元素的总和?
【问题讨论】:
只需使用itertools.count 获取计数器,使用itertools.islice 获取所需数量的元素(您可以迭代这些实例,但它们不会创建列表!):
>>> from itertools import count, islice
>>> sum(islice(count(1, step=4), 100)) # get the first 100 elements and sum them
19900
islice 也支持启动/停止:
>>> sum(islice(count(1, step=4), 101, 200)) # 101st element to 200th
59499
【讨论】:
内置类range 完全符合您在Python 3 中的要求。在Python 2 中,使用xrange。反而。例如:
for i in range(1, 401, 4): ...
range 对象不包含完整列表。它只记录开始、结束和步长。迭代器也会记录当前位置。
在 Python 2 中使用 xrange 很重要,因为 range 函数将返回整个列表,这与您想要的完全相反。
a = range(1, 401, 4)
sum(a)
将计算您想要的总和并允许您在之后重复使用a。
关于数字 401 的注释
范围的结尾是独占的。有几个常用公式可以获取范围内正确数量的元素。 start + count * step 是我在这里选择的,因为它是最简单的。它也是将count 而非count + 1 元素分配给该范围的最大数字。 start + (count - 1) * step + 1 是为您提供count 元素的最小数字的公式。由于您需要 100 个元素,因此 398、399 或 400 的最终值将得到与 401 相同的结果。
【讨论】:
range 对象描述为生成器并不准确。它是一个序列对象,而不是一个迭代器。除了重用它,您还可以执行len(range(...)) 和range(...)[index_or_slice] 之类的操作,并且它可以工作。生成器无法做到这一点。
yield 表达式的函数)或使用生成器表达式来创建一个。您可以编写自己的迭代器类,但这与生成器不同。如果你想拥有__len__ 和__getitem__ 方法,你可能希望你的类型是一个序列(如range 是)而不是一个迭代器。
__call__ 方法定义一个类,该方法执行 yield,该怎么办?
你可以写一个生成器:
def ir(start=1, end=400, step=4):
while True:
yield start
start+=step
if start>=end: break
或者,如果您想要特定数量的元素:
def ir(start=1, n=100, step=4):
cnt=0
while True:
yield start
cnt+=1
start+=step
if cnt>=n: break
然后总结:
>>> sum(ir())
19900
【讨论】:
您可以使用带有sum 的生成器来避免首先创建列表:
result = sum(x for x in range(1, 401, 4))
正如评论中提到的@Mad Physicist,您甚至不需要x for x 部分:
result = sum(range(1, 401, 4))
【讨论】:
x for x in... 几乎没有必要。