Elixir如何高效获取列表中前n个符合条件的元素?
获取列表前n个匹配元素并提前终止迭代
我有一个列表,想要获取其中前n个符合特定条件的元素。当然,我不想对所有列表元素应用条件判断,而是收集到n个符合条件的元素后就停止迭代。
我没能找到用推导式实现的方法,最终自己实现了一个递归的解决方案,但觉得这种常见模式应该有标准库方法可以简化,请问Elixir标准库中有没有合适的方法?
你可以使用Elixir标准库的Enum.reduce_while/3来实现,它支持提前终止迭代,完全满足你的需求,比手动递归更简洁优雅。
基础实现
def first_matches(list, n, pred) do list |> Enum.reduce_while({[], 0}, fn item, {matched, count} -> cond do count >= n -> # 已收集够n个元素,终止迭代 {:halt, {matched, count}} pred.(item) -> # 元素符合条件,加入结果,计数+1,继续迭代 {:cont, {matched ++ [item], count + 1}} true -> # 元素不符合,跳过,继续迭代 {:cont, {matched, count}} end end) |> elem(0) end
性能优化版
上面的实现中matched ++ [item]是O(k)操作(k为当前已匹配元素数),如果列表较大,可以改用反向收集最后反转的方式提升性能:
def first_matches(list, n, pred) do list |> Enum.reduce_while({[], 0}, fn item, {reversed_matched, count} -> cond do count >= n -> {:halt, {reversed_matched, count}} pred.(item) -> {:cont, {[item | reversed_matched], count + 1}} true -> {:cont, {reversed_matched, count}} end end) |> elem(0) |> Enum.reverse() end
核心逻辑说明
Enum.reduce_while/3是实现提前终止迭代的核心:它遍历集合时,处理函数返回:cont, new_acc就继续迭代,返回:halt, final_acc则立刻终止遍历- 我们用元组
{已匹配元素集合, 当前匹配计数}作为累积状态,每找到一个符合条件的元素就更新计数,当计数达到n时直接终止,避免遍历剩余元素
内容的提问来源于stack exchange,提问作者user1934428
相关产品推荐
相关产品推荐

