4

可能重复:
Python:查找与谓词匹配的序列中的第一个元素

Python标准库中是否有封装以下控制流模式的高阶函数?

>>> def find(pred, coll):
...   for x in coll:
...     if pred(x):
...       return x
... 
>>> find(lambda n : n % 2 == 0, [3, 5, 8, 9, 6])
8
>>> find(lambda n : n % 2 == 0, [3, 5, 7, 9, 6])
6
>>> find(lambda n : n % 2 == 0, [3, 5, 7, 9, 1])
4

4 回答 4

11

您可以组合ifilterislice获得第一个匹配的元素。

>>> list(itertools.islice(itertools.ifilter(lambda n: n % 2 == 0, lst), 1))
[8]

但是,我不会认为这比您发布的原始代码更具可读性或更好。包裹在一个函数中会更好。由于next只返回一个元素,因此不再需要islice

def find(pred, iterable):
    return next(itertools.ifilter(pred, iterable), None)

None如果没有找到元素,则返回。

但是,您仍然在每个循环中调用谓词函数的速度相当慢。请考虑改用列表推导式或生成器表达式:

>>> next((x for x in lst if x % 2 == 0), None)
8
于 2012-10-17T07:11:37.817 回答
4

itertools.ifilter()可以做到这一点,如果你只是抓住结果迭代的第一个元素。

itertools.ifilter(pred, col1).next()

同样,生成器对象也可以(同样,从生成的生成器中取出第一项):

(i for i in col1 if i % 2 == 0).next()

由于这两个都是惰性求值的,因此您将只求出满足谓词的第一个元素所需的可迭代输入。请注意,如果没有与谓词匹配,您将获得StopIteration异常。您可以通过使用next()内置来避免这种情况:

next((i for i in col1 if i % 2 == 0), None)
于 2012-10-17T07:12:11.687 回答
2

我不知道有这样的功能,但您可以使用生成器表达式并获取第一个结果。

x = (x for x in [3,5,8,9,6] if (lambda n: n % 2 == 0)(x))
y = x.next()

要不就

y = (x for x in [3,5,8,9,6] if (lambda n: n % 2 == 0)(x)).next()
于 2012-10-17T07:16:10.543 回答
2
(x for x in coll if pred(x)).next()

Raises StopIteration if the item isn't found (which might be preferable to returning None, especially if None is a valid return value).

于 2012-10-17T07:16:20.567 回答