HiveBrain v1.2.0
Get Started
← Back to all entries
patternMinor

Divide number by factors

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
dividenumberfactors

Problem

I'm learning F#.
The code below gets a number e.g. 100 and list of factors and should divide that number by the factors without any rest. (There is an actual code I've got in C#, but this is F# port).

I especially didn't liked equalsDifference function.. any better solution?

namespace RozbijaczApp
module Rozbijacz =
    let precision = 2

    let minUnit = 1m / (pown 10m precision)

    let round x = System.Math.Round(decimal x, precision, System.MidpointRounding.AwayFromZero)

    let mainMapper factor factorSum x = 
        round (x * factor / factorSum)

    let equalsDifference minUnit (difference: decimal) (l: decimal list) =
        let listSize = List.length l
        let mutable acc = difference

        [for i in [0..listSize-1] do
            let element = l |> List.item i
            if acc <> 0m then
                if difference = minUnit then
                        acc  List.sum 
        let result = factors |> List.map (fun x -> mainMapper number factorsSum x)
        let controlSum = result |> List.sum 
        let difference = number - controlSum
        printfn "Difference %O" difference
        // add or substract diffenernce by minUnit for results
        let fixResult = equalsDifference minUnit difference result
        let finalControlSum = fixResult |> List.sum 
        let finalDifference = number - finalControlSum
        printfn "Final difference %O should by zero"finalDifference

        fixResult


and usage:

let factors = [0.2m;0.3m;0.4m]
        let results = Rozbijacz.divider 100m factors
        printfn "Result: %A" results


ok, as you suggested map is better:

```
let equalsDifference minUnit (difference: decimal) (l: decimal list) =
let listSize = List.length l
let mutable acc = difference

let resp = l |> List.map (fun element -> (
if acc <> 0m then
if difference = minUnit then
acc <- acc + minUnit
element - minUnit
else

Solution

Instead of using mutable variables, it is possible to apply the fold:

let equalsDifference minUnit difference l =
    l
    |> List.fold
        (fun (acc,xs) element -> 
               if acc <> 0m then
                  if difference = minUnit then
                         acc + minUnit, (element - minUnit)::xs
                     else
                         acc, element::xs
                  else
                     acc - minUnit, (element + minUnit)::xs
               else
                  acc, element::xs)
        (difference, [])
    |> snd
    |> List.rev

Code Snippets

let equalsDifference minUnit difference l =
    l
    |> List.fold
        (fun (acc,xs) element -> 
               if acc <> 0m then
                  if difference < 0m then
                     if element >= minUnit then
                         acc + minUnit, (element - minUnit)::xs
                     else
                         acc, element::xs
                  else
                     acc - minUnit, (element + minUnit)::xs
               else
                  acc, element::xs)
        (difference, [])
    |> snd
    |> List.rev

Context

StackExchange Code Review Q#133472, answer score: 2

Revisions (0)

No revisions yet.