我正在学习地图和折叠函数。我正在尝试编写一个函数,该函数接受一个列表并返回一个列表,其中包含原始值中的所有值,每个值后面都是该值的double。
Example: add_dbls [2;5;8] = [2;4;5;10;8;16]我尝试的每一件事都会产生一个列表,而不是一个列表。我正努力想出一种更好的方法,使用地图或折叠(或两者兼而有之)。
这是我最初想出来的。我理解为什么这会返回一个列表,但不知道如何修复它。任何想法都将不胜感激!
let add_dbls list =
match list with
| h::t -> map (fun a-> [a;(a*2)]) list
| [] -> []另外,我的地图功能:
let rec map f list =
match list with
| h::t -> (f h)::(map f t)
| [] -> []发布于 2018-02-20 05:00:12
应该很简单地看到,List.map总是返回与输入列表相同长度的列表。但你想要一张两倍长的单子。所以List.map不能为你工作。
您可以使用List.fold_left或List.fold_right解决这个问题。如果你在切换到折叠后仍然有困难,你可以用新的信息更新你的问题。
更新
折叠功能(左折叠)的类型如下:
('a -> 'b -> 'a) -> 'a -> 'b list -> 'a因此,折叠函数接受一个累积的答案和列表中的一个元素,并返回一个新的累积答案。
你折叠的功能如下:
fun a b -> a::b::(b*2)它尝试使用::运算符向累积列表的末尾添加新元素。但这不是::操作符所做的。它向列表的开头添加一个元素。
没有特别好的方法将元素添加到列表的末尾。这是故意的,因为这是一个缓慢的操作。
当使用左折叠时,您需要协调一致,以反向顺序建立结果,并可能在最后将其逆转。或者您可以使用右折叠(通常不是尾递归)。
发布于 2018-02-20 11:43:13
你就快到了。正如您所观察到的,由于我们得到了列表列表,我们需要将其扁平化以获得最终列表。List.concat函数正是这样做的:
let add_dbls list =
let l =
match list with
| h::t -> List.map (fun a -> [a;(a*2)]) list
| [] -> []
in
List.concat l下面是计算所需输出的更新函数。现在add_dbls [2;5;8] = [2;4;5;10;8;16]的输出。尽管这样做有效,但它可能并不有效,因为它在原始列表中为每个项目分配了一个新列表。下面是同一个函数的变化,不同的特性取决于l的大小。
(* Safe version - no stack overflow exception. Less efficient(time and size) than add_dbls3 below. *)
let add_dbls2 l =
List.fold_left
(fun acc a -> (a*2)::a::acc)
[]
l
|> List.rev
(* Fastest but unsafe - stack overflow exception possible if 'l' is large - fold_right is not tail-recursive. *)
let add_dbls3 l =
List.fold_right
(fun a acc -> a::(a*2)::acc)
l
[]https://stackoverflow.com/questions/48878080
复制相似问题