Find maximum, minimum and average in F#

2019-04-09 03:56发布

问题:

I want to find maximum, minimum and average in an array without .NET in F#. I used this code but it is not working:

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

回答1:

I fixed your code for 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

To find max, min and avg, using your approach:

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)

But note you can do just:

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


回答2:

While the answers already posted are perfectly valid as to why your posted code doesn't work, I would argue that using a loop and a mutable variable isn't very ... functional. So I thought I would post a more F# - idiomatic way of solving it.

You state you "can't use .NET". I am guessing you mean you can't use any of the built-in functions or .NET libraries. Of course, that also means that you can implement them yourself using F# primitives.

One common function in the functional world is fold, which simply applies a function to all elements of a sequence, while keeping the return of that function in an accumulator. The built-in version is Seq.fold, but since we can't use that, we'll define one ourselves:

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

This is a recursive function which applies the accFn function to each element, and then calling itself with the remainder of the array. When it gets passed an empty array, recursion terminates.

When we have that, let's define some simple functions to pass into 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

Once we have that, the solution to the stated problem is simple:

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


回答3:

There are some logical problem to calculate max here. And the placement of printfn will print max each time it changes. The following code works:

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()