我想要一种惯用的方法来查找匹配谓词的列表中的第一个元素。
当前的代码相当难看:
[x for x in seq if predicate(x)][0]
我想过把它改成:
from itertools import dropwhile
dropwhile(lambda x: not predicate(x), seq).next()
但肯定有更优雅的……如果它返回一个None值,而不是在没有找到匹配时引发异常,那就更好了。
我知道我可以这样定义一个函数:
def get_first(predicate, seq):
for i in seq:
if predicate(i): return i
return None
但是,如果已经内置了提供相同功能的内置功能,那么开始用这样的实用函数填充代码是相当乏味的(人们可能不会注意到它们已经存在,所以它们往往会随着时间的推移而重复出现)。
查找序列seq中与谓词匹配的第一个元素:
next(x for x in seq if predicate(x))
或者仅仅是:
Python 2:
next(itertools.ifilter(predicate, seq))
Python 3:
next(filter(predicate, seq))
如果谓词不匹配任何元素,这些语句将引发StopIteration异常。
如果没有这样的元素则返回None:
next((x for x in seq if predicate(x)), None)
Or:
next(filter(predicate, seq), None)
J.F. Sebastian的回答是最优雅的,但正如fortran指出的那样,需要python 2.6。
对于Python版本< 2.6,这里是我能想到的最好的:
from itertools import repeat,ifilter,chain
chain(ifilter(predicate,seq),repeat(None)).next()
或者,如果你以后需要一个列表(list处理StopIteration),或者你需要的不仅仅是第一个,但仍然不是全部,你可以用islice来做:
from itertools import islice,ifilter
list(islice(ifilter(predicate,seq),1))
更新:
虽然我个人使用一个被称为first()的预定义函数来捕获StopIteration并返回None,这里有一个可能的改进:避免使用过滤器/过滤器:
from itertools import islice,chain
chain((x for x in seq if predicate(x)),repeat(None)).next()
查找序列seq中与谓词匹配的第一个元素:
next(x for x in seq if predicate(x))
或者仅仅是:
Python 2:
next(itertools.ifilter(predicate, seq))
Python 3:
next(filter(predicate, seq))
如果谓词不匹配任何元素,这些语句将引发StopIteration异常。
如果没有这样的元素则返回None:
next((x for x in seq if predicate(x)), None)
Or:
next(filter(predicate, seq), None)