Calculate the rolling averages for general type arrays

Category: visual studio fsharp

Question

zydjohn on Sat, 20 May 2017 17:36:46


I'm trying to calculate the rolling averages of every four values in an array and add those values to a separate array. 
My original array list is called data and it contains values from 1 to 9
let data = [| 1; 2; 3; 4; 5; 6; 7; 8; 9 |]
When it calculates rolling averages, it should do it in an way like this:
first average = (1+2+3+4)/4
second average = (2+3+4+5)/4
third average = (3+4+5+6)/4
and so on
so the second array list, should contain these values
[| 2.5, 3.5, 4.5, 5.5, 6.5, 7.5 |]

I found this question for C#, and someone gave the answer in C#:

You can use LINQ like this:
List<double> averages = Enumerable.Range(0, numlist.Count - 3).
                              Select(i => numlist.Skip(i).Take(4).Average()).
                              ToList();

I want to do the same in F#, but I also want to use general type, so function can take either array of integers or floats.
The rolling number can be different, as long as it is less than the number of the original array.  For example:
I want to calculate the rolling averages of every three, four, five values in an array and save the rolling averages in another array.
And return the result array, if the rolling number is more than the the number of the original array, then return an empty array.
Thanks

Replies

Mr. Tines on Sat, 20 May 2017 20:11:23


> so function can take either array of integers or floats.

This runs into the same annoying problem with operators inferring integer types, so you can't just write the obvious

let rollingMean (series : 'a seq) n =
   series
   |> Seq.windowed n
   |> Seq.map Seq.average;;

However, you can use the "inline" hack to defer type resolution, and expect that the results will be non-integral and write

let inline rollingMean (series : 'a seq) n = series |> Seq.map float |> Seq.windowed n |> Seq.map Seq.average;;

which will do what you want for any type with a float conversion.