【问题标题】:Python: how to calculate the sum of a list without creating the whole list first?Python:如何在不先创建整个列表的情况下计算列表的总和?
【发布时间】: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个元素的总和?

【问题讨论】:

    标签: python list sum yield


    【解决方案1】:

    只需使用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
    

    【讨论】:

      【解决方案2】:

      内置类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 相同的结果。

      【讨论】:

      • 将 Python 3 的 range 对象描述为生成器并不准确。它是一个序列对象,而不是一个迭代器。除了重用它,您还可以执行len(range(...)) 和range(...)[index_or_slice] 之类的操作,并且它可以工作。生成器无法做到这一点。
      • @Blckknght。如果生成器定义了适当的方法,那绝对是。但你是对的,range 不是生成器,因为你不能调用 next。
      • 您不能在生成器对象上定义方法。您可以通过调用生成器函数(其中包含yield 表达式的函数)或使用生成器表达式来创建一个。您可以编写自己的迭代器类,但这与生成器不同。如果你想拥有__len__ 和__getitem__ 方法,你可能希望你的类型是一个序列(如range 是)而不是一个迭代器。
      • @Blckknght 如果您使用 __call__ 方法定义一个类,该方法执行 yield,该怎么办?
      • 我们很清楚,我即将修正我的答案,因为我基本上同意你的看法。只是在手机上超级慢
      【解决方案3】:

      你可以写一个生成器:

      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
      

      【讨论】:

      • 为什么要重新发明轮子?
      • 因为您可以在自定义函数中包含更多内容,例如跳过第 20 天或模拟 Gregorian Calendar
      【解决方案4】:

      您可以使用带有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... 几乎没有必要。
      • 它在技术上称为生成器表达式,而不是推导式:stackoverflow.com/documentation/python/292/…
      猜你喜欢
      • 2021-02-08
      • 1970-01-01
      • 2023-03-03
      • 1970-01-01
      • 2021-02-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多