查找与条件匹配的行中的最后一个元素
Posted
技术标签:
【中文标题】查找与条件匹配的行中的最后一个元素【英文标题】:Find the last element in a row that matches a criterion 【发布时间】:2020-02-23 10:23:46 【问题描述】:除了这个问题“Get the first item from an iterable that matches a condition”之外,我还需要第一个匹配之前的元素。或完全等价:一行中与条件匹配的最后一个元素。例如,如果我需要此列表中第一个非素数之前的最后一个素数 [2, 3, 4, 5, 6, 7, 8, 9]
,则答案是 3。如果没有这样的元素,结果可能是 None、异常或默认值。
直接的解决方案是:
result = None
for x in numbers:
if is_prime(x):
result = x
else:
break
是否有一个简单的单线可以解决任务?
【问题讨论】:
【参考方案1】:不确定是否有更简单的方法。我的方法需要itertools.takewhile
。
-
使用
itertools.takewhile
在不再满足条件后停止迭代以创建素数列表直到第一个非素数出现,即[2, 3]
然后使用list[-1]
获取列表的最后一个元素。
如果列表为空,请使用(list or [None])[-1]
,以便返回None
import itertools
result = ([x for x in itertools.takewhile(lambda n: is_prime(n), numbers)] or [None])[-1]
collections.deque()
from collections import deque
result = (deque((itertools.takewhile(lambda n: is_prime(n), numbers)), maxlen=1) or [None]).pop()
【讨论】:
此解决方案从生成器创建完整列表。失去可读性我们也失去了效率。理想的解决方案应该只保留以前和当前的元素。【参考方案2】:您可以使用zip
和islice
构造一个迭代器,它有自己的“未来”可用。
next(
filter(
lambda pair: isprime(pair[1]), # The predicate applied to a pair
zip(xs, islice(xs, 1, None)) # The iterator and its 'future'
),
(None, None) # A default pair in case no matches are found
)[0] # Retrieve the 'current' entry from the matching pair
在每个步骤中,您都有一对您可以认为是(present, future)
,谓词将应用于future
。最后,我们解包present
,它表示迭代器中最后一个不匹配的条目。
请注意,如所示,此实现不会返回列表中的最后一个条目,因为本质上,如果您将[a, b, c]
压缩到其自己的移位版本,您最终会得到一个比另一个短的。你可以使用zip_longest
(来自itertools
)来克服这个问题,但你需要在你的谓词中处理fillvalue
(通常是None
)。
正如评论中所述,这对生成器不起作用,因为它会消耗生成器。但是,使用折叠(Python 中的reduce
)会变得更容易。首先,在更“Pythonic”的演示中,函数看起来像这样:
def fold(hist, cur):
stop, prev = hist
if stop:
return hist
if isprime(cur):
return (True, prev)
return (False, cur)
元组的第一个元素用作“停止”标记,第二个元素是我们的“针”。您可以将其与 reduce 一起使用:
reduce(fold, xs, (False, None))[1]
这并不完全是“一个衬里”,但我们可以将其压缩成lambda
:
reduce(lambda z, x: (z if z[0] else ((1, z[1]) if isprime(x) else (0, x))), xs, (0, None))[1]
【讨论】:
有趣的解决方案。更接近我的预期。然而,这对生成器不起作用,但如果将表达式zip(xs, islice(xs, 1, None))
替换为仅接受一次 xs
的东西,那将起作用。
你可以通过折叠来做到这一点。我会将其添加到答案中。以上是关于查找与条件匹配的行中的最后一个元素的主要内容,如果未能解决你的问题,请参考以下文章
Groovy集合遍历 ( 使用集合的 find 方法查找集合元素 | 闭包中使用 == 作为查找匹配条件 | 闭包中使用 is 作为查找匹配条件 | 闭包使用 true 作为条件 | 代码示例 )
Groovy集合遍历 ( 使用集合的 find 方法查找集合元素 | 闭包中使用 == 作为查找匹配条件 | 闭包中使用 is 作为查找匹配条件 | 闭包使用 true 作为条件 | 代码示例 )(代