我不知道是否有一个原因,有没有first(iterable)
在Python内置的功能,有点类似于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,这是一个单一的文件,所以你甚至不必安装它使用它。
事实上,这里的几乎整个源代码(从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)
它不计算谓词两次(因为你必须做,如果返回刚刚模式),它不使用黑客像当地人内涵。
但它有两个发电机嵌套其中的逻辑将决定只使用一个。 因此,一个更好的解决方案将是很好。
有没有在你的问题有些含糊不清。 你的第一个和正则表达式例子定义意味着有一个布尔测试。 但分母例如明确有一个if子句; 因此它只的每个整数恰好是真正的巧合。
它看起来像未来的结合,itertools.ifilter会给你想要的东西。
match = next(itertools.ifilter(None, (regex.match(big_text) for regex in regexes)))
有一个在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
哈斯克尔利用了你刚才所描述的东西,作为函数take
(或部分功能take 1
,技术上)。 Python的食谱有书面发电机包装,作为执行相同的功能take
, takeWhile
和drop
在Haskell。
但是,为什么这不是一个内置的,你猜我的一样好。