【问题标题】:How to count non-null elements in an iterable?如何计算可迭代对象中的非空元素?
【发布时间】:2011-03-24 12:48:26
【问题描述】:

我正在为以下 sn-p 寻找更好/更 Pythonic 的解决方案

count = sum(1 for e in iterable if e)

【问题讨论】:

  • 你的方式有什么问题或'unpythonic'?
  • 生成器表达式是 Pythonic。你的意思是更短吗?
  • OP,在 Python 中准确了解什么是非空,什么不是非空。例如,sum(1 for e in [False, 0, '', [], (), [''], (''), [False], (False,), None] if e) 实际上计算为 3 而不是 0,因为奇怪的是嵌套序列 [['']][[False]][(False,)] 算作非空值,但 [('')] 没有,[!无论如何,总的来说,如果我们保证列表是平坦的,那么您提供的代码很好并且足以完成任务。

标签: python iterator list-comprehension idioms


【解决方案1】:
len(filter(None, iterable))

使用None 作为filter 的谓词只是说使用项目的真实性。 (也许更清楚的是len(filter(bool, iterable))

【讨论】:

  • +1 这很好而且很快(比我电脑上的生成器表达式快大约 8 倍)。 bool 似乎比 None 稍慢
  • 快速解决方案,但 O(N) 额外内存是一个减号。我的列表通常有 1000000 个元素,因此仅使用 1MB 内存来计算非零元素并不是那么有效。另外,我认为您没有为 gc 计时以回收过滤器生成的列表。
  • 这只是 len(list(iterable)) 的一种复杂方式。
  • 这将排除 False 和 None。尽管 OP 提出了问题,但标题暗示计算非空,而不是非空等价物。我来这里是为了寻找类似filter(None, mylist) 的东西,它仍然会将 False 视为不为空。 (我删除了反对票,因为此解决方案适用于所述问题,而不是标题所暗示的问题。)
【解决方案2】:

老实说,我想不出比你现有的更好的方法了。

嗯,我想人们可能会争论“更好”,但我认为你不太可能找到更短、更简单、更清晰的东西。

【讨论】:

    【解决方案3】:

    大多数 Pythonic 是编写一个小的辅助函数并将其放入您可信赖的“实用程序”模块(或适当包的子模块,当您有足够的时候;-):

    import itertools as it
    
    def count(iterable):
      """Return number of items in iterable."""
      return sum(1 for _ in iterable)
    
    def count_conditional(iterable, predicate=None):
      """Return number of items in iterable that satisfy the predicate."""
      return count(it.ifilter(predicate, iterable))
    

    如何您选择如何实现这些实用程序并不重要(您可以随时选择在 Cython 中重新编码其中的一些,例如,如果使用这些实用程序的应用程序的某些分析显示它是有用):关键是将它们作为您自己有用的实用函数库,具有喜欢的名称和调用模式,以使您最重要的应用程序级别代码更清晰,更易读,更简洁,如果你把它塞满了内联的扭曲!-)

    【讨论】:

    • “你喜欢的调用模式”:非作者代码阅读者可能会知道(例如)sum(map(bool, iterable)) 做了什么,而无需询问 SO 或查找 TFM ...不得不在其他地方找到一个定义会破坏阅读流程。
    【解决方案4】:
    sum(not not e for e in iterable)
    

    【讨论】:

    • 哇。这个答案已经足够老了,以至于bool(e) 不存在。
    【解决方案5】:

    正如 cmets 中所述,标题与问题有些不协调。如果我们坚持标题,即计算非空元素,则OP的解决方案可以修改为:

    count = sum(1 for e in iterable if e is not None)
    

    【讨论】:

      【解决方案6】:

      这不是最快的,但可能对代码高尔夫很方便

      sum(map(bool, iterable))
      

      【讨论】:

      • 仅在 Python 2.x 中 - 在 Python 3 中,map 返回生成器,而不是列表。
      • 您也可以使用 itertools 中的 imap。
      • 如果迭代器包含任何评估为 false 的值(如空字符串、零、False、空列表...),这将不起作用
      • @Quartz,就像这里的大多数答案一样,它相当于问题正文中提供的 sn-p,而不是标题:)
      • @Quartz,JohnLaRooy,我将标题更正为 “sum non-null elements” 并添加了警告注释,我认为这可以解决所有问题?
      【解决方案7】:

      可能最 Pythonic 的方式是编写不需要计数函数的代码。

      通常最快的方法是编写你最擅长的函数样式并继续改进你的样式。

      编写一次经常阅读代码。

      顺便说一句,您的代码并没有按照您的标题所说的那样做!考虑到浮点数的舍入误差,计算非 0 个元素并不简单,即 False 为 0..

      如果列表中没有浮点值,可以这样做:

      def nonzero(seq):
        return (item for item in seq if item!=0) 
      
      seq = [None,'', 0, 'a', 3,[0], False] 
      print seq,'has',len(list(nonzero(seq))),'non-zeroes' 
      
      print 'Filter result',len(filter(None, seq))
      
      """Output:
      [None, '', 0, 'a', 3, [0], False] has 5 non-zeroes
      Filter result 3
      """
      

      【讨论】:

      • 不,那不是,这只是len(list(item for item in seq if item!=0)) 的一种复杂的说法。这实际上是更少的 Pythonic。当我们想要做的只是计算一个项目是否非零时,nonzero(seq) 没有必要构造一次性中间列表。在生成器表达式中这样做意味着我们不需要构造中间列表 AFAIK。
      【解决方案8】:

      如果您只是想查看可迭代对象是否不为空,那么这可能会有所帮助:

      def is_iterable_empty(it):
          try:
              iter(it).next()
          except StopIteration:
              return True
          else:
              return False
      

      其他答案需要 O(N) 时间才能完成(有些需要 O(N) 记忆;好眼力,约翰!)。此函数需要 O(1) 时间。如果您真的需要长度,那么其他答案将对您有更多帮助。

      【讨论】:

      • 嗯(1)这会更短:is_iterable_empty = lambda it: not any(it)(2)如果可迭代对象不为空并且是迭代器,这不会消耗第一个元素吗?
      • 实际上,您使用any 函数的解决方案实际上不会在所有情况下都做同样的事情。如果迭代器只返回 False 布尔对象(或空列表等),那么您的 lambda 会给出误报。我确信这段代码可以缩短,但我喜欢提供扩展代码进行演示。至于消耗第一个对象,是的,它会,但是这里的所有解决方案都将消耗至少一个元素(大多数消耗全部)。没有解决此问题的好方法,但只要记录在案,那么一切都应该没问题。
      【解决方案9】:

      这是一个 O(n) 运行时间和 O(1) 额外内存的解决方案:

      count = reduce(lambda x,y:x+y, imap(lambda v: v>0, iterable))
      

      希望有帮助!

      【讨论】:

        猜你喜欢
        • 2018-08-19
        • 1970-01-01
        • 2014-11-12
        • 2011-05-13
        • 1970-01-01
        • 2012-11-05
        • 1970-01-01
        • 2021-11-14
        • 1970-01-01
        相关资源
        最近更新 更多