从列表中取出符合条件的前n个元素

问题描述 投票:0回答:2

我有一个列表,想知道列表中符合特定条件的前 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 库中没有任何东西可以让我的实现更简单吗?

elixir
2个回答
0
投票

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 备忘单感兴趣。


0
投票

有两个模块用于操作类似列表的事物。

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
© www.soinside.com 2019 - 2024. All rights reserved.