如何编写通用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'
。
答案 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
可与float
,decimal
和int
一起使用。
然后像在原始解决方案中一样使用它:
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