【问题标题】:f# get product of 4 adjacent numbers in an arrayf# 获取数组中 4 个相邻数字的乘积
【发布时间】:2012-05-31 16:15:52
【问题描述】:

我正在尝试获取数组中 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 但给定一个 'a * 'b -> 'a * 'b 统一 ''a' 和 ''a * 'b -> 'a * 'b' 时产生的类型是无限的


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

【问题讨论】:

  • 数组还是列表?您的问题是数组,但您的代码正在使用列表...

标签: .net f#


【解决方案1】:

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

因此,为了完整起见,这里有一种使用现有函数以更声明方式解决问题的方法:

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

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

【讨论】:

  • Seq.windowed 返回滑动窗口;他的问题中的代码使用了连续的组。
  • @Daniel :所选答案也使用滑动窗口,所以我想这毕竟是 OP 真正想要的。
  • @ildjarn:也许……也许他没有注意到。
  • 嗯,跳过除第四个元素之外的所有元素可以使用Seq.mapi 后跟Seq.filter 来完成。
【解决方案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 不是一个好的起点。请注意可能会发生整数溢出(我还没有在我的函数中解决这个问题)。

【讨论】:

  • 知道了,问题是我使用(a,b) 而不是a b 最后也错过了b::c::d
【解决方案3】:

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

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 忽略最后的任何部分组(就像您的代码一样)。

【讨论】:

  • 我真的不知道什么是连续和滑动,所以我会展示我在做什么,这个:projecteuler.net/problem=11,所以这个函数是欧拉问题 11 的一部分或解决方案
  • @ChuckNorris :给定[1;2;3;4;5;6;7;8],你想关注什么[1;2;3;4][2;3;4;5][5;6;7;8]?其他答案给出了前者,这个(和你的问题)给出了后者。
  • 列表中所有可能的 4 个相邻数字:1234、2345、3456 ... 5678
  • @ChuckNorris :那将是滑动。 ;-]
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-05-21
  • 1970-01-01
  • 2012-07-25
  • 2015-04-15
  • 1970-01-01
  • 1970-01-01
  • 2013-12-31
相关资源
最近更新 更多