0

我是函数式编程(ReasonML / OCaml)的新手。

我有一个花车清单。我想获取列表的前三个非零项,仅此而已。项目可以是正数、负数和零。

在提取前三个非零浮点数之前如何限制递归?

我正在考虑做类似的事情:

switch (list) {
  | [first, second, third, ...rest] => (first +. second +. third) /. 3.0
  | _ => 0.0
};

但是我怎么能保证first,secondthird是非零浮点数呢?如果是,则递归丢弃它们,直到找到三个非零浮点数 - 或 return 0.0

4

2 回答 2

1

使用递归的一个更好的方法是让它更通用:而不是找到第一个非零的 3,让我们找到第n一个非零。

下面是一个OCaml的实现,我不知道Reason。

let rec find_n l n ~f =
  if n = 0 then []
  else match l with
  | [] -> failwith "Cannot find enough items"
  | h::t ->
      if f h then
        h :: (find_n t (n-1) ~f)
      else
        find_n (t n ~f)

这是函数的签名:

val find_n : 'a list -> int -> f:('a -> bool) -> 'a list = <fun>

这里发生了很多事情,但并没有那么糟糕。这里的逻辑如下:

如果我想要列表中的 3 个项目:

  • 如果它的头部匹配,那么我需要在尾部寻找 2 个项目。
  • 否则,我仍然需要在尾部寻找 3 个项目。

其他一切都只是附加逻辑:

  • 如果我正在寻找 0 个项目,我就完成了。
  • 如果列表是空的,我还需要寻找更多的项目,我失败了。

关于尾递归的一句话

不幸的是,上面的实现不是尾递归的,这意味着它在大列表上会失败。使函数尾递归的一种常用技术是使用累加器acc在下面的代码中)来存储中间结果。

然后,我们将这个额外的逻辑封装在一个本地辅助函数(通常称为loopor aux)中,这样累加器就不会出现在函数的签名中。

let find_n l n ~f =
  let rec loop l' n' acc =
    if n' = 0 then acc else
      match l' with
      | [] -> failwith "Cannot find enough items"
      | h::t ->
          if f h then
            loop t (n' - 1) (h::acc)
          else
            loop t n' acc
  in
  loop l n []
于 2017-09-14T08:44:10.190 回答
0

知道了!

List.filer可用于过滤掉等于零的元素。

let filtered = List.filter (fun item => item != 0.0) list;
switch (filtered) {
  | [first, second, third, ...rest] => (first +. second +. third) /. 3.0
  | _ => 0.0
};
于 2017-09-14T03:25:30.033 回答