user12929792
user12929792

Reputation:

Find mean of list in F#

I'm trying to find the average of a list

Here's what I have so far

let rec avg aList =
    match aList with
    | head::tail -> head+avg(tail)
    | [] -> 0

This obtains the sum. I've tried head+avg(tail)/aList.Length, but it gives me an incorrect result as I don't know exactly what that's doing

Any help would be appreciated

Upvotes: 1

Views: 1009

Answers (3)

Kevin Avignon
Kevin Avignon

Reputation: 2903

The simplest way of doing this is using the average high-order function from the List module. You can do this on a single line with

let myAverage = aList |> List.average

Upvotes: 3

Asti
Asti

Reputation: 12687

For an average, you'd want two things, the sum and the number of items. Using List.length would mean traversing the list again. We can do those two things at the same time - by using a tuple.

This operation is known as folding (or sometimes aggregation). We apply the folding function, gathering our state as we traverse the list without mutating anything.

let avg aList =
    let rec accumulate (sum, count) list =
        match list with
        | head::tail -> accumulate (sum + head, count + 1) tail
        | [] -> (sum, count)
    let sum, count = accumulate (0, 0) aList
    let average = sum / count
    average

You can generalize this using fold.

let avg aList =        
    let sum, count = 
        List.fold (fun (sum, count) current -> (sum + current, count + 1)) (0,0) aList
    let average = sum / count
    average

The generic math version:

let inline avg (list: 'a list) =        
    let rec accumulate (sum, count) list =
           match list with
           | head::tail -> accumulate (Checked.(+) sum head, count + 1) tail
           | [] -> (sum, count)
    let sum, count = accumulate (LanguagePrimitives.GenericZero<'a>, 0) list
    let average = LanguagePrimitives.DivideByInt sum count
    average

Upvotes: 4

Filipe Carvalho
Filipe Carvalho

Reputation: 628

let avg aList =
    let rec sum = function
        | head :: tail -> head + (sum tail)
        | [] -> 0.
    sum aList / (aList |> List.length |> float)

let res = avg [ 2.; 4.; 6. ]
printfn "%A" res

I'm not sure this is the best way to do it tho.

Upvotes: 0

Related Questions