f#获取数组中4个相邻数字的乘积

时间:2012-05-31 16:15:52

标签: .net f#

我正在尝试在阵列中获得4个相邻数字的最大乘积 这就是我现在所得到的:

let max4 line =
    let rec loop acc = function
        |a :: b :: c :: [] -> acc
        |a :: b :: c :: d :: tl -> loop (max(acc, a*b*c*d)) tl
        |_ -> 0
    loop 0 line

我在max(,)上说出了编译错误:

  

错误FS0001:类型不匹配。期待一个       '但是给了一个       'a *'b - > 'a *'b在统一''a'和''a *'b - >时,结果类型将是无限的。 'a *'b'


有人知道这段代码有什么问题吗? (或其他解决方案)

3 个答案:

答案 0 :(得分:5)

作为使用显式递归的替代方法,您还可以使用现有的F#库函数来解决此问题。这就是大多数F#数据处理的编写方式,但学习如何手动编写递归函数总是很好(因为有时候需要它们)。

所以,为了完整起见,这里有一种方法可以使用现有函数更加声明地解决问题:

let max4 line = 
  line |> Seq.windowed 4 
       |> Seq.map (Seq.reduce (*))
       |> Seq.max

第一行将列表转换为4元素数组(窗口)的序列。然后将其传递给Seq.map,将窗口转换为元素的乘积。为此,我使用Seq.reduce使用指定的函数减少序列(在本例中为窗口),这里是(*)运算符。最后,要查找产品的最大元素,可以使用Seq.max函数。

答案 1 :(得分:2)

假设输入是整数列表:

let max4 line =
    let rec loop acc = function
        | x1::(x2::x3::x4::_ as xs) -> loop (max acc (x1*x2*x3*x4)) xs
        |_ -> acc
    loop System.Int32.MinValue line

你犯了一些错误:

  • 内置max功能采用咖喱形式max: 'a -> 'a -> 'a
  • 要在您的函数中处理的下一个案例应该是b::c::d::tl,而不仅仅是tl
  • 产品可能是负数,因此0不是一个好的起点。请注意整数溢出可能发生(我仍然没有在我的函数中解决)。

答案 2 :(得分:1)

其他两个答案总和滑动窗口,但在你的问题中它们是连续的。如果你想要后者,你可以定义这样一个函数:

let groupsOf n items =
  if n <= 0 then invalidArg "n" "must be greater than zero"
  if List.isEmpty items then invalidArg "items" "empty list"
  let rec loop i acc items =
    seq {
      match i, items with
      | 0, [] -> yield List.rev acc
      | _, [] -> ()
      | 0, _ ->
        yield List.rev acc
        yield! loop n [] items
      | _, x::xs -> yield! loop (i - 1) (x::acc) xs
    }
  loop n [] items

然后使用类似于Tomas的代码:

let max4 line = 
  line |> groupsOf 4 
       |> Seq.map (Seq.reduce (*))
       |> Seq.max

groupsOf会忽略最后的任何部分组(代码也是如此)。