为什么没有第一(迭代器)内置在Python的功能?
题
我不知道是否有一个原因,有一个在Python的内置功能,有点类似于first(iterable)
和any(iterable)
没有all(iterable)
(它可能是一个STDLIB模块中藏的地方,但我没有看到它在itertools
) 。 first
将执行,使得能够避免不必要的(和潜在的无限数目)的操作的短路发生器评价;即。
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]
和短路节省大量不必要的处理。
解决方案
如果你有一个迭代器,你可以调用它的next
方法。是这样的:
In [3]: (5*x for x in xrange(2,4)).next()
Out[3]: 10
其他提示
有一个称为“第一” 一个的PyPI包,这是否:
>>> from first import first
>>> first([0, None, False, [], (), 42])
42
下面是你将如何使用返回第一个奇数,例如:
>> first([2, 14, 7, 41, 53], key=lambda x: x % 2 == 1)
7
如果你只是想从迭代器返回的第一个元素无论是真还是假,做到这一点:
>>> first([0, None, False, [], (), 42], key=lambda x: True)
0
这是一个非常小的封装:它仅包含此功能,它没有依赖关系,以及它适用于Python 2和3,这是一个单一的文件,所以你甚至不必安装它使用它。 p>
在事实上,这里的几乎整个源代码(来自2.0.1版本,通过希内克Schlawack,在MIT许可下发布的):
def first(iterable, default=None, key=None):
if key is None:
for el in iterable:
if el:
return el
else:
for el in iterable:
if key(el):
return el
return default
我问了一个类似的问题最近(它得到了标记为重复现在这个问题)。我担心的也是,我会喜欢用内建的只有的解决找到一个发电机的第一个真正的价值的问题。然后自己的解决方案是这样的:
x = next((v for v in (f(x) for x in a) if v), False)
有关找到第一个正则表达式的匹配的示例中,这是这样的(不是第一匹配图案!):
patterns = [ r'\d+', r'\s+', r'\w+', r'.*' ]
text = 'abc'
firstMatch = next(
(match for match in
(re.match(pattern, text) for pattern in patterns)
if match),
False)
它不计算谓词两次(因为你必须做,如果返回刚才的模式),它并没有在内涵使用像当地人黑客。
但是它有两个发电机嵌套其中,所述逻辑将决定只使用一个。因此,一个更好的解决办法将是不错的。
有在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
有在你的问题有些含糊不清。您的第一并正则表达式示例的定义意味着存在一个布尔测试。但分母例如明确有一个if子句;因此它只的每个整数恰好是真巧合。
它看起来像未来的结合,itertools.ifilter会给你想要的东西。
match = next(itertools.ifilter(None, (regex.match(big_text) for regex in regexes)))
的Haskell利用了您刚刚描述的内容,作为函数take
(或作为部分功能take 1
,在技术上)。 Python的食谱具有书面发电机封装的执行相同功能如take
,takeWhile
和drop
在Haskell。
但是,为什么这不是一个内置的,你猜我的一样好。