通过折叠乘法列表

时间:2018-11-17 20:28:39

标签: ocaml

因此,我目前正在尝试找出如何编写一个函数,该函数采用2个相等长度的列表,并通过折叠将两个列表的相同位置相乘,并将结果作为新的List返回。

eg) let prodList [1; 2; 3] [4; 5; 6] ;; 
==> (through folding) ==> [1*4; 2*5; 3*6]
==> result = [4; 10; 18]

我觉得我需要使用List.combine,因为它将把需要相乘的值放入元组中。之后,我无法弄清楚如何以允许我乘以值的方式拆分元组。这是我到目前为止的内容:

let prodLists l1 l2 =
  let f a x =  (List.hd(x)) :: a in
  let base = [] in
  let args = List.rev (List.combine l1 l2) in
  List.fold_left f base args

我在正确的轨道上吗?

3 个答案:

答案 0 :(得分:0)

您可以使用fold_left2来折叠两个相同长度的列表。该文档可以为您提供更多详细信息(https://caml.inria.fr/pub/docs/manual-ocaml/libref/List.html):

val fold_left2 : ('a -> 'b -> 'c -> 'a) -> 'a -> 'b list -> 'c list -> 'a

List.fold_left2 f a [b1; ...; bn] [c1; ...; cn]f (... (f (f a b1 c1) b2 c2) ...) bn cn。如果确定两个列表的长度不同,请提高Invalid_argument

另一种方法是按照您的建议折叠合并的输出,我建议您在看下面的解决方案之前自己尝试。

解决方案:

let prod_lists l s =
  List.rev (List.fold_left2 (fun acc a b -> (a * b) :: acc) [] l s);;

let prod_lists' l s =
  List.fold_left (fun acc (a, b) -> (a * b) :: acc) [] (List.rev (List.combine l s));;

答案 1 :(得分:0)

首先让我注意到,使用fold来实现此操作似乎有些强制,因为您必须同时遍历两个列表。但是,折叠合并了单个列表的元素。尽管如此,这是一个实现。

let e [] = []

let f x hxs (y::ys) = (x*y) :: hxs ys 

let prodList xs ys = List.fold_right f xs e ys

看起来有点复杂,所以让我解释一下。

对折的通用属性

首先,您应该了解fold_right的以下属性。

h xs = fold_right f xs e 

当且仅当

h [] = e
h (x::xs) = f x (h xs)

这意味着,如果我们以下面的递归形式编写列表的乘法,则可以使用ef来使用fold来编写它。请注意,尽管我们正在操作两个列表,所以h接受两个参数。

基本案例-空列表

将两个空列表相乘会返回一个空列表。

h [] [] = []

如何在上面的表格中写这个?只是抽象第二个参数。

h [] = fun [] -> []

所以

e = fun [] -> []`

或等效地

e [] = []

递归案例-非空列表

h (x::xs) (y::ys) = x*y :: h xs ys

或者,仅使用一个参数,

h (x::xs) = fun -> (y::ys) -> x*y :: h xs ys

现在,我们需要以h (x::xs) = f x (h xs)的形式重写此表达式。它可能看起来很复杂,但是我们只需要对xh xs进行抽象。

h (x::xs) = (fun x hxs -> fun (y::ys) -> x*y :: hxs ys) x (h xs)

所以我们有f

定义
f = fun x hxs -> fun (y::ys) -> x*y :: hxs ys

或等效地

f x hxs (y::ys) = x*y :: hxs ys

解决方案

确定了ef之后,我们根据上述属性的第一个方程式将其插入折叠。我们得到

h xs = List.fold_right f xs e

或等效地

h xs ys = List.fold_right f xs e ys

了解实施情况

请注意,List.fold_right f xs e的类型为int list -> int list,因此折线在列表上构建了一个函数,给定某些ys会将其与给定参数xs相乘。

对于空xs,您将期望空ys并返回空结果,因此

e [] = fun [] -> []

对于递归情况,f中的函数fold_right必须实现x::xs的解决方案。因此,xs采用f类型的xint类型的函数hxs来实现尾部的乘法,并且必须实现{ {1}}。

int list -> int list

因此,x::xs构造了一个将f x hxs = fun (y::ys) -> x*y :: hxs ys f相乘的函数,然后将其应用于x并将{{1}到列表。

答案 2 :(得分:0)

您大多有正确的想法;您需要先combine(其他语言zip)两个列表,然后在每个元组上map

let prod_lists l1 l2 =
  List.combine l1 l2
  |> List.map (fun (a, b) -> a * b)

关键是您可以使用(a, b)在该元组上进行模式匹配。

如果您不想使用fold,也可以rev在合并列表上,然后map,结果。