我是函数式编程的新手(ReasonML / OCaml)。
我有一张浮动列表。我想获得列表中的前三个非零项目而不是更多。项目可以是正数,负数和零。
在提取前三个非零浮点数之前,如何限制递归?
我在想做类似的事情:
switch (list) {
| [first, second, third, ...rest] => (first +. second +. third) /. 3.0
| _ => 0.0
};
但我怎样才能保证first
,second
和third
是非零浮点数?如果是,则递归丢弃它们,直到找到三个非零浮点数 - 或者返回0.0
。
答案 0 :(得分:1)
使用递归更好的方法是使它更通用:不是找到第一个非零的3,让我们找到.
第一个非零。
下面是一个OCaml实现,我不知道Reason。
n
这是函数的签名:
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)
这里有很多事情,但并不是那么糟糕。这里的逻辑如下:
如果我想要列表中的3个项目:
- 如果它的头部匹配,那么我需要在尾部找两个项目。
- 否则,我仍然需要在尾巴中寻找3个项目。
其他一切只是额外的逻辑:
- 如果我要找0件,我就完蛋了。
- 如果列表为空,我仍然需要查找更多项目,我就失败了。
不幸的是,上面的实现不是tail-recursive,这意味着它将在大型列表上失败。使函数尾递归的常用技术是使用 accumulator (下面代码中的val find_n : 'a list -> int -> f:('a -> bool) -> 'a list = <fun>
)来存储中间结果。
然后,我们将这个额外的逻辑封装在本地辅助函数(通常称为acc
或loop
)中,以便累加器不会显示在函数的签名中。
aux
答案 1 :(得分: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
};