Reputation:
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
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
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
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