【问题标题】:Getting the first non None value from list从列表中获取第一个非 None 值
【发布时间】:2013-09-03 05:24:30
【问题描述】:

给定一个列表,有没有办法获得第一个非无值?如果是这样,pythonic 的方法是什么?

例如,我有:

  • a = objA.addreses.country.code
  • b = objB.country.code
  • c = None
  • d = 'CA'

在这种情况下,如果 a 是 None,那么我想得到 b。如果 a 和 b 都为 None,我想得到 d。

目前我正在按照(((a or b) or c) or d) 的方式做一些事情,还有其他方法吗?

【问题讨论】:

    标签: python list


    【解决方案1】:

    你可以使用next():

    >>> a = [None, None, None, 1, 2, 3, 4, 5]
    >>> next(item for item in a if item is not None)
    1
    

    如果列表只包含无,它将抛出StopIteration 异常。如果您想在这种情况下使用默认值,请执行以下操作:

    >>> a = [None, None, None]
    >>> next((item for item in a if item is not None), 'All are Nones')
    All are Nones
    

    【讨论】:

    • 我会添加一个 try: except StopIteration: 来处理仅包含 None 项目的列表。但这是一个很好的答案。
    • @Germano 更新了答案,请检查。顺便说一句,Jon 的回答应该被接受——他是第一个为无列表提出解决方案的人。
    • 我打了个嗝......感谢那些指出它的人......我认为这个答案还是写出来更好;)
    • @kevlar1818,如果你省略了“不是无”,那么它会像对待无一样对待 0 和“”(至少在我的 python 版本中)
    • @kevlar1818 :D 迟到总比没有好
    【解决方案2】:

    我认为这是处理一小组值时最简单的方法

    firstVal = a or b or c or d
    

    将始终返回在某些情况下有效的第一个非“Falsey”值(假设您不期望任何可能评估为 false 的值,正如@GrannyAching 在下面指出的那样)

    【讨论】:

    • 如果有任何值为 False 的值,例如:0、''、[]、()、False,则不会
    • 感谢指正,我忽略了(更新后的帖子)
    • 这很好,很简洁。我想要第一个非空字符串。
    【解决方案3】:

    first_true 是在Python 3 docs 中找到的itertools 配方:

    def first_true(iterable, default=False, pred=None):
        """Returns the first true value in the iterable.
    
        If no true value is found, returns *default*
    
        If *pred* is not None, returns the first item
        for which pred(item) is true.
    
        """
        # first_true([a,b,c], x) --> a or b or c or x
        # first_true([a,b], x, f) --> a if f(a) else b if f(b) else x
        return next(filter(pred, iterable), default)
    

    可以选择实现后一种配方或导入more_itertools,这是一个随itertools 配方等提供的库:

    > pip install more_itertools
    

    用途:

    import more_itertools as mit
    
    a = [None, None, None, 1, 2, 3, 4, 5]
    mit.first_true(a, pred=lambda x: x is not None)
    # 1
    
    a = [None, None, None]
    mit.first_true(a, default="All are None", pred=lambda x: x is not None)
    # 'All are None'
    

    为什么要使用谓词?

    “第一个非None”项目与“第一个True”项目不同,例如[None, None, 0] 其中0 是第一个非None,但它不是第一个True 项。谓词允许 first_true 可用,确保迭代中任何第一次看到的、非无的、虚假的项目仍然返回(例如 0False)而不是默认值。

    a = [None, None, None, False]
    mit.first_true(a, default="All are None", pred=lambda x: x is not None)
    # 'False'
    

    【讨论】:

    • 太棒了!可惜这是标准库的一部分。
    • 配方是文档的一部分。你只需要自己实现它。
    【解决方案4】:

    当列表中的项目计算成本很高时,例如在

    first_non_null = next((calculate(x) for x in my_list if calculate(x)), None)
    
    # or, when receiving possibly None-values from a dictionary for each list item:
    
    first_non_null = next((my_dict[x] for x in my_list if my_dict.get(x)), None)
    

    那么您可能希望避免重复计算并简化为:

    first_non_null = next(filter(bool, map(calculate, my_list)), None)
    
    # or:
    
    first_non_null = next(filter(bool, map(my_dict.get, my_list)), None)
    

    由于使用了生成器表达式,因此仅对第一个项目执行计算,直到生成真值。

    【讨论】:

    • 可以在 python 3 中使用 map 代替生成器表达式。first_non_null = next(filter(bool, map(my_dict.get, my_list)), None)
    • 确实更优雅,我已经根据你的建议更新了答案
    【解决方案5】:

    改编自以下内容(如果您愿意,可以单行):

    values = (a, b, c, d)
    not_None = (el for el in values if el is not None)
    value = next(not_None, None)
    

    这采用第一个非None 值,或者返回None

    【讨论】:

      【解决方案6】:

      首先要提一下SQL中存在这样的函数,叫做coalesce。在 Python 中没有发现这样的东西,所以我自己用@alecxe 的配方做了一个。

      def first_not_none(*values):
          return next((v for v in values if v is not None), None)
      

      在这种情况下真的很有帮助:

      attr = 'title'
      document[attr] = first_not_none(cli_args.get(attr), document_item.get(attr),
                                      defaults_item.get(attr), '')
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-02-18
        • 2015-12-23
        • 1970-01-01
        • 1970-01-01
        • 2022-12-17
        • 1970-01-01
        相关资源
        最近更新 更多