从列表中获取第一个非None值


68

给定一个列表,有没有办法获取第一个非值?而且,如果是这样,这样做的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),是否还有另一种方法?

Answers:


125

您可以使用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

5
我将添加一个try: except StopIteration:以处理仅包含无项目的列表。但这是一个很好的答案。
Germano

1
@德国更新了答案,请检查。顺便说一句,乔恩(Jon)的答案应该被接受-他是第一个为“仅列出”列表提出解决方案的人。
alecxe 2013年

1
我的大脑打了。...感谢那些指出的人……我认为无论如何都应该写出更好的答案;)
乔恩·克莱门茨

3
@ kevlar1818,如果省略了“不为空”,则将其视为0和“”,就像对待“无”(至少在我的python版本中一样)
jcfollower 2013年

1
@ kevlar1818:迟到总比不到好
alecxe

13

first_trueitertoolsPython 3文档中找到的配方:

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)

您可以选择实施后一种配方或import 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是可用的,确保在仍返回迭代任何第一次看到,非无,falsey项(例如0False)而不是默认的。

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

优秀的!遗憾的是,这是标准库的一部分。
GLRoman

好吧,食谱是文档的一部分。您只需要自己实施即可。
pylang

8

我认为这是处理少量值时最简单的方法(同样适用于列表理解):

firstVal = a or b or c or d

始终会返回在某些情况下有效的第一个非“ False”值(假设您不希望出现任何可能被@GrannyAching指出为false的值)


2
否,如果有任何值为False的值,例如:0,'',[],(),False
Granny Aching

1
感谢您的更正,我忽略了这一点(更新后的帖子)
DannyMoshe19年

这很简洁。我想要第一个非空字符串。
小哺乳动物

6

从以下内容进行调整(如果需要,可以单线):

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

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


我不明白 这不会仅仅是打印True还是False
thefourtheye

@thefourtheye是的-有点打......感谢您指出
乔恩·克莱门茨

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, my_list)), None)

由于使用了生成器表达式,因此仅对前一项执行计算,直到生成真实值为止。


你可以在Python 3.使用地图,而不是一台发电机的表达 first_non_null = next(filter(bool, map(my_dict.get, my_list)), None)
Azeezah中号

这确实更加优雅,我已根据您的建议更新了答案
Lars Blumberg
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.