我想从符合条件的列表中获取第一项.重要的是,生成的方法不会处理整个列表,这可能非常大.例如,以下功能就足够了:
def first(the_iterable, condition = lambda x: True):
for i in the_iterable:
if condition(i):
return i
Run Code Online (Sandbox Code Playgroud)
这个函数可以用这样的东西:
>>> first(range(10))
0
>>> first(range(10), lambda i: i > 3)
4
Run Code Online (Sandbox Code Playgroud)
但是,我想不出一个好的内置/单线来让我这样做.如果我不需要,我不特别想复制这个功能.是否有内置方法可以使第一个项目符合条件?
Ale*_*lli 415
在Python 2.6或更高版本中:
如果您想要StopIteration在没有找到匹配元素的情况下被引发:
next(x for x in the_iterable if x > 3)
如果你想要default_value(例如None)返回:
next( (x for x in the_iterable if x>3), default_value)
请注意,在这种情况下,您需要在生成器表达式周围添加一对括号 - 当生成器表达式不是唯一参数时,它们总是需要它们.
我看到大多数答案都坚决地忽略了next内置内容,所以我认为出于一些神秘的原因,他们100%专注于2.5及更早的版本 - 没有提到Python版本的问题(但后来我没有提到确实提到next内置的答案,这就是我认为有必要自己提供答案的原因 - 至少"正确的版本"问题以这种方式记录在案;-).
在2.5中,如果迭代器立即完成.next(),迭代器的方法会立即引发StopIteration- 例如,对于您的用例,如果迭代中没有项满足条件.如果你不关心(也就是说,你知道必须至少有一个令人满意的项目)那么只需使用.next()(最好使用genexp,next在Python 2.6中更好地使用内置行).
如果你做护理,包裹的东西在一个功能,你就先在自己的Q指示,似乎最好的,当你提出的功能实现就好了,你可以选择使用itertools,一个for...: break循环或genexp,或try/except StopIteration作为函数体,如各种答案所示.这些替代方案中没有太多附加值,所以我会选择你最初提出的简单版本.
Car*_*orc 22
def first(iterable, condition = lambda x: True):
"""
Returns the first item in the `iterable` that
satisfies the `condition`.
If the condition is not given, returns the first item of
the iterable.
Raises `StopIteration` if no item satysfing the condition is found.
>>> first( (1,2,3), condition=lambda x: x % 2 == 0)
2
>>> first(range(3, 100))
3
>>> first( () )
Traceback (most recent call last):
...
StopIteration
"""
return next(x for x in iterable if condition(x))
Run Code Online (Sandbox Code Playgroud)
Jos*_*ush 19
我喜欢这个答案.但是,由于在没有项目时next()引发StopIteration异常,我将使用以下代码段来避免异常:
a = []
item = next((x for x in a), None)
Run Code Online (Sandbox Code Playgroud)
例如,
a = []
item = next(x for x in a)
Run Code Online (Sandbox Code Playgroud)
会引发StopIteration例外;
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
Run Code Online (Sandbox Code Playgroud)
Mat*_*son 13
与using类似ifilter,您可以使用生成器表达式:
>>> (x for x in xrange(10) if x > 5).next()
6
Run Code Online (Sandbox Code Playgroud)
在任何一种情况下,你可能想要捕捉StopIteration,以防没有元素满足你的条件.
从技术上讲,我想你可以这样做:
>>> foo = None
>>> for foo in (x for x in xrange(10) if x > 5): break
...
>>> foo
6
Run Code Online (Sandbox Code Playgroud)
它可以避免不得不try/except阻止.但这似乎有点模糊和滥用语法.
Python 3中最有效的方法是以下方法之一(使用类似的示例):
next(i for i in range(100000000) if i == 1000)
Run Code Online (Sandbox Code Playgroud)
警告:该表达式也适用于Python 2,但在该示例中使用的range是在Python 3中返回一个可迭代对象,而不是像Python 2这样的列表(如果要在Python 2中构造一个可迭代对象,请使用xrange)。
请注意,该表达式避免在comprehension表达式中构造一个列表next([i for ...]),这将导致在过滤元素之前创建一个包含所有元素的列表,并导致处理整个选项,而不是一次停止迭代i == 1000。
next(filter(lambda i: i == 1000, range(100000000)))
Run Code Online (Sandbox Code Playgroud)
警告:这在Python 2中不起作用range,xrange由于filter创建列表而不是迭代器(效率低下)而无法替换,并且该next函数仅适用于迭代器。
如其他响应中所述,next如果要避免在不满足条件时引发异常,则必须在函数中添加一个额外参数。
next(filter(lambda i: i == 1000, range(100000000)), False)
Run Code Online (Sandbox Code Playgroud)
使用这种样式时,您需要将comprehension表达式包含()在其中,以避免出现SyntaxError: Generator expression must be parenthesized if not sole argument:
next((i for i in range(100000000) if i == 1000), False)
Run Code Online (Sandbox Code Playgroud)
该itertools模块包含迭代器的过滤器函数.可以通过调用next()它来获取筛选迭代器的第一个元素:
from itertools import ifilter
print ifilter((lambda i: i > 3), range(10)).next()
Run Code Online (Sandbox Code Playgroud)
对于旧版本的Python,其中下一个内置不存在:
(x for x in range(10) if x > 3).next()
Run Code Online (Sandbox Code Playgroud)
通过使用
(index for index, value in enumerate(the_iterable) if condition(value))
Run Code Online (Sandbox Code Playgroud)
可以检查the_iterable中第一个项的值的条件,并获得其索引,而无需评估the_iterable中的所有项.
要使用的完整表达式是
first_index = next(index for index, value in enumerate(the_iterable) if condition(value))
Run Code Online (Sandbox Code Playgroud)
这里first_index假定在上面讨论的表达式中标识的第一个值的值.
对于使用 Python 3.8 或更高版本的任何人,我建议使用PEP 572 - 赋值表达式中所述的“赋值表达式” 。
if any((match := i) > 3 for i in range(10)):
print(match)
Run Code Online (Sandbox Code Playgroud)
以下是 3 个替代方案,并附有基准。
next()单线:
values = list(range(1, 10000000))
value = next((x for x in values if x > 9999999), None)
Run Code Online (Sandbox Code Playgroud)
这是使用函数的替代方法next(),速度大约快 2%-5%:
values = list(range(1, 10000000))
def first(items):
for item in items:
if item > 9999999: # Your condition
return item
return None # Default value
value = first(values)
Run Code Online (Sandbox Code Playgroud)
这是一个在所有情况下都可以用于替换的函数next()。性能大约慢 300%:
values = list(range(1, 10000000))
def first(items, condition, default = None):
for item in items:
if condition(item):
return item
return default
value = first(values, lambda x: x > 9999999, None)
Run Code Online (Sandbox Code Playgroud)
内存消耗相当。
这是基准。