2017-09-14 44 views
0

我是功能编程(RationalML/OCaml)的新手。限制递归浮动列表的前三个元素

我有一个浮动列表。我想获得列表中的前三个非零项目,而不是更多。项目可以是正数,负数和零。

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

我的想法做类似的:

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

但我怎么能保证firstsecondthird非零花车?如果是,则递归丢弃它们直到找到三个非零浮点数 - 或返回0.0

回答

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个物品。

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

  • 如果我在寻找空的,我就完了。
  • 如果列表为空,我仍然需要查找更多项目,则失败。

关于尾递归的词

不幸的是,上面的实现不是tail-recursive,这意味着它将在大型列表失败。使函数尾递归的常用技术是使用一个累加器acc在下面的代码中)来存储中间结果。然后,我们将这个额外的逻辑封装在本地帮助函数(通常称为loopaux)中,以便累加器不会出现在函数的签名中。

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 [] 
+1

非常感谢!对于那些希望看到ReasonML语法的用户,可以使用此工具在OCaml和RationalML片段之间进行转换。 https://reasonml.github.io/try/?ocaml=DYUwLgBAZglgdgEwPpwsCqB+UIF4IGFHEmlnkWVXU2130ONMUBQBokATiAMZoD2-AA5oA5BnEBDHn1xtCMHHHH4ADBDAALEKml8QwAM4h5RALaSwPTWIgB3GFtOEAPhADaAXQgBaAHzQkjDADloQAEQAwpJwcPyQsIgQOvwArgDmNo4gZobhzgRumgBcxZD+BcSK0BA2WjqVJMCCIpAAFMq+EACMAJQQbSXFer2NhAbGY0TNwhoSEHry8PIzIuioXkA –

0

Got it!

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 
}; 
+4

请注意,即使在找到三个非零浮点数后,这将遍历整个列表。 –