F # универсальная функция для вычисления среднего - PullRequest
0 голосов
/ 19 декабря 2018

Как написать общую функцию 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 голосов
/ 19 декабря 2018

Это один из способов создания общей функции 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
0 голосов
/ 19 декабря 2018

Обратите внимание, что суммирование последовательности с последующим делением на длину уязвимо для ошибок переполнения.Было бы лучше использовать инкрементный алгоритм, например, реализовать один из алгоритмов из этого вопроса на 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
0 голосов
/ 19 декабря 2018

Для начала эта функция уже существует в F # и называется Seq.average.Если вы делаете это только для того, чтобы иметь эту функцию, вы можете перестать читать сейчас.Если вы делаете это как личное учебное упражнение, читайте дальше.: -)

Документация F # для 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...