81

我想知道first(iterable)Python 内置函数中是否有 no 的原因,有点类似于any(iterable)and all(iterable)(它可能隐藏在某个 stdlib 模块中,但我没有在 中看到它itertools)。first将执行短路生成器评估,从而可以避免不必要的(并且可能是无限数量的)操作;IE

def identity(item):
    return item

def first(iterable, predicate=identity):
    for item in iterable:
        if predicate(item):
            return item
    raise ValueError('No satisfactory value found')

通过这种方式,您可以表达以下内容:

denominators = (2, 3, 4, 5)
lcd = first(i for i in itertools.count(1)
    if all(i % denominators == 0 for denominator in denominators))

显然,在这种情况下你不能这样做list(generator)[0],因为生成器不会终止。

或者,如果您有一堆正则表达式要匹配(当它们都具有相同的groupdict界面时很有用):

match = first(regex.match(big_text) for regex in regexes)

list(generator)[0]通过避免和短路正匹配,您可以节省大量不必要的处理。

4

6 回答 6

50

Python 2中,如果你有一个迭代器,你可以调用它的next方法。就像是:

>>> (5*x for x in xrange(2,4)).next()
10

Python 3中,您可以使用next内置的迭代器:

>>> next(5*x for x in range(2,4))
10
于 2009-07-03T00:18:22.677 回答
19
于 2013-04-23T16:11:47.973 回答
12
于 2013-08-14T07:58:09.020 回答
6

你的问题有些模棱两可。您对first和正则表达式示例的定义暗示有一个布尔测试。但是分母示例明确地有一个 if 子句;所以每个整数恰好是真的只是一个巧合。

看起来 next 和 itertools.ifilter 的组合会给你你想要的。

match = next(itertools.ifilter(None, (regex.match(big_text) for regex in regexes)))
于 2009-07-03T00:38:09.017 回答
6

在 itertools 中有一个“切片”迭代器。它模拟了我们在 python 中熟悉的切片操作。你正在寻找的是类似于这样的东西:

myList = [0,1,2,3,4,5]
firstValue = myList[:1]

对迭代器使用 itertools 的等价物:

from itertools import islice
def MyGenFunc():
    for i in range(5):
        yield i

mygen = MyGenFunc()
firstValue = islice(mygen, 0, 1)
print firstValue 
于 2013-09-03T10:30:54.447 回答
4

Haskell 将您刚才描述的内容用作函数take(或技术上的部分函数take 1)。 Python Cookbook编写了生成器包装器,它们执行与Haskell taketakeWhile和相同的功能。drop

但至于为什么这不是内置的,你的猜测和我的一样好。

于 2009-07-03T00:22:29.300 回答