我有一个列表,想知道列表中符合特定条件的前 n 个元素。当然,我不想将我的条件应用于所有列表元素,而是在收集完 n 个元素后立即停止迭代。
我找不到一种理解的方法,所以最后我排除了我自己的解决方案。
U.first_matches(li, n, pred)
返回 n
中与谓词 li
:匹配的第一个
pred
元素
defmodule U do
def first_matches([], _n, _pred) do
[]
end
def first_matches(_list, 0, _pred) do
[]
end
def first_matches(list, n, pred) do
first_el = Kernel.hd(list)
if pred.(first_el) do
[first_el|U.first_matches(Kernel.tl(list), n-1, pred)]
else
U.first_matches(Kernel.tl(list), n, pred)
end
end
end
据我测试过,这似乎可行,但我不敢相信我需要编写自己的递归函数来实现如此常见的模式。 Elixir 库中没有任何东西可以让我的实现更简单吗?
Enum.take_while/2
:
iex(1)> Enum.take_while(1..100, fn x -> x <= 10 end)
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
您可能还对 Enum 备忘单感兴趣。
Enum
通常返回一个列表,但Stream
返回延迟计算的结果流。如果您主要使用 Stream
函数,那么您就满足了不评估条件次数超过必要次数的要求。
例如,假设您有从 1 到 100 的整数,并且您想找到前 10 个偶数。为此,您可以获取输入列表,过滤偶数项,从流中获取前 10 个项,然后将结果具体化到列表中。
require Integer
1..100 |>
Stream.filter(&Integer.is_even/1) |>
Stream.take(10) |>
Enum.to_list()
# [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]
您还可以使用
Enum
函数作为最后一次调用来获取列表,并跳过单独的 Enum.to_list/1
调用。
这使得您提出的辅助函数也非常简单
def first_matches(list, n, pred) do
list |> Stream.filter(pred) |> Enum.take(n)
end