F#泛型函数计算均值

时间:2018-12-19 07:28:45

标签: f#

如何编写通用F#函数以计算集合的均值? 我尝试过:

let inline mean x = 
    let length = x |> Seq.length
    let sum = x |> Seq.sum
    LanguagePrimitives.DivideByInt sum length

这似乎对浮点数和小数有效,但令人惊讶的是不适用于int,并显示错误The type 'int' does not support the operator 'DivideByInt'

3 个答案:

答案 0 :(得分:2)

首先,此功能已存在于F#中,并称为Seq.average。如果您只是为了拥有该功能而这样做,则可以立即停止阅读。如果您将其作为个人学习练习,请继续阅读。 :-)

F# documentation on DivideByInt在这里有答案:

  

如果类型支持DivideByInt,则该类型支持精确除法(浮点除法),而不是整数除法,后者会四舍五入到最接近的整数结果。

     

仅当元素类型支持精确除法时,像Seq.average之类的功能才起作用。如果尝试对整数序列使用Seq.average,则会收到一条错误消息,指出元素类型必须实现DivideByInt。通常,可以通过使用Seq.averageBy并将强制转换添加到浮点值来解决此错误。

因此,要使您的mean函数在整数上起作用,您需要按以下方式编写它:

let intMean (x : int seq) = 
    let length = x |> Seq.length
    let sum = x |> Seq.map float |> Seq.sum
    LanguagePrimitives.DivideByInt sum length

答案 1 :(得分:2)

这是创建通用mean函数的一种方法。

首先创建一个更通用的divideByInt

type Helper = Helper of int with
    static member (&/)(Helper b, a) = a /          b 
    static member (&/)(Helper b, a) = a / (float   b)
    static member (&/)(Helper b, a) = a / (decimal b)

let inline divideByInt a b = Helper b &/ a

此版本的divideByInt可与floatdecimalint一起使用。

然后像在原始解决方案中一样使用它:

let inline mean x = 
    let length = x |> Seq.length
    let sum    = x |> Seq.sum
    divideByInt sum length

并像这样测试它:

mean [5. ; 3.] |> printfn "%A"   // 4.0
mean [5  ; 3 ] |> printfn "%A"   // 4

答案 2 :(得分:2)

请注意,将序列求和然后除以长度很容易发生溢出错误。最好使用增量算法,例如实现this question on math.stackexchange.com中的一种算法。

例如:

let inline mean xs =
    xs |> Seq.map float
       |> Seq.fold (fun (mean, n) x -> mean + (x-mean) / (float n), n+1) (0.0, 1)
       |> fst