给定一个列表,有没有办法获取第一个非值?而且,如果是这样,这样做的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:
您可以使用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
first_true
是itertools
在Python 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项(例如0
,False
)而不是默认的。
a = [None, None, None, False]
mit.first_true(a, default="All are None", pred=lambda x: x is not None)
# 'False'
我认为这是处理少量值时最简单的方法(同样适用于列表理解):
firstVal = a or b or c or d
始终会返回在某些情况下有效的第一个非“ False”值(假设您不希望出现任何可能被@GrannyAching指出为false的值)
从以下内容进行调整(如果需要,可以单线):
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
?
当列表中的项目计算成本很高时,例如
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)
由于使用了生成器表达式,因此仅对前一项执行计算,直到生成真实值为止。
first_non_null = next(filter(bool, map(my_dict.get, my_list)), None)
try:
except StopIteration:
以处理仅包含无项目的列表。但这是一个很好的答案。