我想从匹配条件的列表中获得第一项。产生的方法不能处理整个列表,这一点很重要,因为列表可能相当大。例如,以下函数就足够了:
def first(the_iterable, condition = lambda x: True):
for i in the_iterable:
if condition(i):
return i
这个函数可以这样使用:
>>> first(range(10))
0
>>> first(range(10), lambda i: i > 3)
4
但是,我想不出一个好的内置/单行程序来让我这样做。如果没有必要,我不想复制这个函数。是否有一种内置的方法来获取匹配条件的第一项?
在Python 3中:
a = (None, False, 0, 1)
assert next(filter(None, a)) == 1
在Python 2.6中:
a = (None, False, 0, 1)
assert next(iter(filter(None, a))) == 1
编辑:我认为这是显而易见的,但显然不是:而不是None,你可以传递一个函数(或一个lambda),检查条件:
a = [2,3,4,5,6,7,8]
assert next(filter(lambda x: x%2, a)) == 3
Python 2.6+和Python 3:
如果你想在没有找到匹配的元素时引发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)
注意,在这种情况下,在生成器表达式周围需要一对额外的圆括号-当生成器表达式不是唯一的参数时,就需要它们。
我看到大多数答案都坚决地忽略了下一个内置版本,所以我假设出于某种神秘的原因,他们100%专注于2.5及以上版本——没有提到python版本的问题(但我在回答中没有看到提到下一个内置版本的问题,这就是为什么我认为有必要自己提供一个答案——至少“正确版本”的问题会以这种方式记录下来;-)。
Python <= 2.5
如果迭代器立即结束,迭代器的.next()方法立即引发StopIteration——也就是说,对于您的用例,如果可迭代对象中没有项满足条件。如果你不在乎(也就是说,你知道至少有一个令人满意的项),那么只需使用.next()(最好用于genexp, Python 2.6或更好的下一个内置代码行)。
如果你真的关心,就像你在Q中第一次指出的那样,将东西包装在函数中似乎是最好的,而你提出的函数实现也很好,你可以选择使用itertools,一个for…: break循环,或genexp,或try/except StopIteration作为函数体,正如各种答案所建议的那样。这些替代方案都没有多少附加价值,所以我会选择你最初提出的极其简单的版本。
Python 3中最有效的方法是以下方法之一(使用类似的示例):
“理解”风格:
next(i for i in range(100000000) if i == 1000)
警告:该表达式也适用于Python 2,但在本例中使用的range在Python 3中返回一个可迭代对象,而不是像Python 2那样返回一个列表(如果你想在Python 2中构造一个可迭代对象,则使用xrange代替)。
注意,表达式避免在理解表达式next([i for…])中构造一个列表,这将导致在筛选元素之前创建一个包含所有元素的列表,并将导致处理整个选项,而不是在i == 1000时停止迭代。
具有“功能性”风格:
next(filter(lambda i: i == 1000, range(100000000)))
警告:这在Python 2中不起作用,甚至用xrange替换range,因为过滤器创建了一个列表而不是迭代器(效率低),下一个函数只适用于迭代器。
默认值
正如在其他响应中提到的那样,如果希望避免在条件不满足时引发异常,则必须向接下来的函数添加一个额外参数。
“功能性”风格:
next(filter(lambda i: i == 1000, range(100000000)), False)
“理解”风格:
使用这种风格,你需要用()包围理解表达式,以避免SyntaxError:如果不是唯一的参数,生成器表达式必须用圆括号括起来:
next((i for i in range(100000000) if i == 1000), False)
你也可以在Numpy中使用argwhere函数。例如:
i)找到“helloworld”中的第一个“l”:
import numpy as np
l = list("helloworld") # Create list
i = np.argwhere(np.array(l)=="l") # i = array([[2],[3],[8]])
index_of_first = i.min()
ii)求第一个随机数> 0.1
import numpy as np
r = np.random.rand(50) # Create random numbers
i = np.argwhere(r>0.1)
index_of_first = i.min()
iii)求最后一个随机数> 0.1
import numpy as np
r = np.random.rand(50) # Create random numbers
i = np.argwhere(r>0.1)
index_of_last = i.max()