将递归限制为浮动列表的前三个元素
Limit recursion to the first three elements of list of floats
我是函数式编程 (ReasonML / OCaml) 的新手。
我有一个花车清单。我想获得列表的前三个非零项,仅此而已。项目可以是正数、负数和零。
在提取前三个非零浮点数之前如何限制递归?
我正在考虑做类似的事情:
switch (list) {
| [first, second, third, ...rest] => (first +. second +. third) /. 3.0
| _ => 0.0
};
但是我如何保证first
、second
和third
是非零浮点数呢?如果是,递归地丢弃它们,直到找到三个非零浮点数——或 return 0.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
};
使用递归执行此操作的更好方法是使其更通用:让我们找到 n
第一个非零值,而不是找到第 3 个非零值。
下面是一个OCaml实现,我不知道原因。
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>
这里发生了很多事情,但还不错。这里的逻辑如下:
If I want 3 items from a list:
- If its head matches, then I need to look for 2 items in the tail.
- Else, then I still need to look for 3 items in the tail.
其他一切都只是额外的逻辑:
- If I'm looking for 0 items, I'm done.
- If the list is empty and I still need to look for more items, I failed.
关于尾递归的一句话
不幸的是,上面的实现不是tail-recursive,这意味着它会在大型列表上失败。使函数尾递归的常用技术是使用累加器(下面代码中的acc
)来存储中间结果。
然后,我们将这个额外的逻辑封装在本地辅助函数(通常称为 loop
或 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 []
我是函数式编程 (ReasonML / OCaml) 的新手。
我有一个花车清单。我想获得列表的前三个非零项,仅此而已。项目可以是正数、负数和零。
在提取前三个非零浮点数之前如何限制递归?
我正在考虑做类似的事情:
switch (list) {
| [first, second, third, ...rest] => (first +. second +. third) /. 3.0
| _ => 0.0
};
但是我如何保证first
、second
和third
是非零浮点数呢?如果是,递归地丢弃它们,直到找到三个非零浮点数——或 return 0.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
};
使用递归执行此操作的更好方法是使其更通用:让我们找到 n
第一个非零值,而不是找到第 3 个非零值。
下面是一个OCaml实现,我不知道原因。
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>
这里发生了很多事情,但还不错。这里的逻辑如下:
If I want 3 items from a list:
- If its head matches, then I need to look for 2 items in the tail.
- Else, then I still need to look for 3 items in the tail.
其他一切都只是额外的逻辑:
- If I'm looking for 0 items, I'm done.
- If the list is empty and I still need to look for more items, I failed.
关于尾递归的一句话
不幸的是,上面的实现不是tail-recursive,这意味着它会在大型列表上失败。使函数尾递归的常用技术是使用累加器(下面代码中的acc
)来存储中间结果。
然后,我们将这个额外的逻辑封装在本地辅助函数(通常称为 loop
或 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 []