【问题标题】:Find maximum, minimum and average in F#在 F# 中查找最大值、最小值和平均值
【发布时间】:2011-12-11 08:20:42
【问题描述】:

我想在 F# 中没有 .NET 的数组中找到最大值、最小值和平均值。 我使用了这段代码,但它不起作用:

let mutable max = 0
let arrX = [|9; 11; 3; 4; 5; 6; 7; 8|]

for i in 0 .. arrX.Length - 2 do
  if (arrX.[i]) < (arrX.[i+1]) then 
       max <- arrX.[i]
       printfn "%i" max

【问题讨论】:

  • 使用 Array.max, Array.min, Array.averageBy float

标签: f# f#-interactive


【解决方案1】:

虽然已经发布的答案对于为什么您发布的代码不起作用是完全有效的,但我认为使用循环和可变变量并不是很... 功能。所以我想我会发布一个更 F# - 惯用的解决方法。

您声明“不能使用 .NET”。我猜你的意思是你不能使用任何内置函数或 .NET 库。当然,这也意味着您可以使用 F# 原语自己实现它们。

函数世界中的一个常见函数是fold,它只是将函数应用于序列的所有元素,同时将该函数的返回值保存在累加器中。内置版本是Seq.fold,但由于我们不能使用它,我们将自己定义一个:

let rec fold accFn arr acc = 
    match arr with
    | [||] -> acc
    | _ -> fold accFn arr.[1..] (accFn arr.[0] acc)

这是一个递归函数,它将accFn 函数应用于每个元素,然后使用数组的其余部分调用自身。当它传递一个空数组时,递归终止。

当我们有了这些,让我们定义一些简单的函数来传递给fold

let min x y =
    if x < y then x 
    else y

let max x y = 
    if x > y then x
    else y

let sum x y = 
    x + y

一旦我们有了这个,解决上述问题的方法就很简单了:

let arrX= [|9; 11; 3; 4; 5; 6; 7; 8|]
let head = arrX.[0]
let avg = (fold sum arrX 0) / arrX.Length
let minValue = fold min arrX head
let maxValue = fold max arrX head

【讨论】:

  • 请注意,fold 的这种实现效率很低,因为它在每次递归迭代之前复制数组的剩余部分。见slice notation。接受一个计数器作为参数并在每次迭代时将i+1 传递给尾部调用会更有效。 (不过仍然可以很好地作为插图)。
【解决方案2】:

我将你的代码修正为 max

let mutable max = 0
let arrX= [|9; 11; 3; 4; 5; 6; 7; 8|]

for i in 0 .. arrX.Length - 1 do
  if max < (arrX.[i]) then 
       max <- arrX.[i]
       printfn "%i" max

使用您的方法查找最大值、最小值和平均值:

let mutable max = System.Int32.MinValue
let mutable min = System.Int32.MaxValue
let mutable sum = 0
let arrX= [|9; 11; 3; 4; 5; 6; 7; 8|]

for i in 0 .. arrX.Length - 1 do
  if max < (arrX.[i]) then 
       max <- arrX.[i]
       printfn "max %i" max
  if min > (arrX.[i]) then 
       min <- arrX.[i]
       printfn "min %i" min
  sum <- sum + arrX.[i]
printfn "-> max is %i" max
printfn "-> min is %i" min
printfn "-> avg is %f" (float sum / float arrX.Length)

但请注意,您可以这样做:

let max = Seq.max arrX
let min = Seq.min arrX
let avg = Seq.averageBy float arrX

【讨论】:

    【解决方案3】:

    这里计算最大值存在一些逻辑问题。 printfn 的位置每次更改时都会打印 max 。以下代码有效:

    let mutable max = 0
    let arrX= [|9; 11; 3; 4; 5; 6; 7; 8|]
    
    for i in 0 .. arrX.Length-1 do
        if max < arrX.[i] then 
            max <- arrX.[i]
    printfn "%i" max
    

    【讨论】:

      【解决方案4】:
      let ofArray f (a : 'T array) =
        let len = a.Length
        let rec aux index ret =
          if index >= len then
            ret
          else
            aux (index+1) (f a.[index] ret)
        aux 1 a.[0]
      
      let maxOfArray (a : 'T array) = ofArray max a
      let minOfArray (a : 'T array) = ofArray min a
      let inline sumOfArray (a : 'T array) = ofArray (+) a
      
      let main() =
        printfn "max: %d" <| maxOfArray arrX
        printfn "min: %d" <| minOfArray arrX
        printfn "ave: %f" <| (sumOfArray arrX |> float) / (arrX.Length |> float)
      
      do main() 
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2016-01-05
        • 2016-12-29
        • 2015-01-16
        • 1970-01-01
        • 1970-01-01
        • 2014-06-11
        • 2017-03-08
        • 2017-07-24
        相关资源
        最近更新 更多