# Divide number by factors

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 < 0m then
if element >= minUnit then
acc <- acc + minUnit
yield element - minUnit
else
yield element
else
acc <- acc - minUnit
yield element + minUnit
else
yield element
]

let divider (number:decimal) factors =
let factorsSum = factors |> 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 < 0m then
if element >= minUnit then
acc <- acc + minUnit
element - minUnit
else
element
else
acc <- acc - minUnit
element + minUnit
else
element
) )
resp


But is this enough? Any F# magic?

• Regarding equalsDifference, why don't you use List.map over l? – Quentin Pradet Jun 30 '16 at 12:19
• The for loop should be List.map – John Palmer Jun 30 '16 at 12:19
• @JohnPalmer Please write all critiques, even trivial ones, in an answer. Comments are for seeking to clarify the question, and may be deleted. – 200_success Jun 30 '16 at 16:27

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 < 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