F#-如何将整数更好地划分为(几乎相等)“存储桶”?

时间:2020-07-13 13:49:33

标签: list f# integer divide

我有一个整数,我希望将其划分为尽可能接近的相等大小的整数“存储桶”列表。 一些例子:

  • 将10除以2应该给我一个清单为“ [5; 5]”(5 + 5 = 10),或
  • 将20除以3应该给我一个清单“ [7; 7; 6]”(7 + 7 + 6 = 20),或
  • 将15除以4应该给我一个清单为“ [4; 4; 4; 3]”(4 + 4 + 4 + 3)之类的东西。

较大的存储桶是位于末端还是位于中间或混合在一起无关紧要-划分进程以进行并行处理,而顺序无关紧要。

我写了一些看起来还可以的代码,但是看起来太乱了,很难推理:

let integerBuckets total divider =
    match total, divider with
    | 0, _  -> [ 0 ]
    | 1, _ -> [ 1 ]
    | _, 0 -> [ total ] // Should  never happen, but checked just in case.
    | _, 1 -> [ total ]
    | _ ->
        let result = (double total) / (double divider)
        let remainder = total % divider
        [ for _ in 0 .. (remainder - 1) -> int (ceil result) ]
            @ [ for _ in 0 .. (divider - remainder - 1) -> int (floor result) ]

integerBuckets 15 4

我真的不喜欢for循环中的数学;容易出错和/或意外更改。但这不只是我不确定的数学知识。

任何人都可以给我一些指导,让我了解如何将其“整理”到更容易阅读的更好的F#中吗?

我不是要有人提供更好的代码片段,而是要提供指向我应该学习的领域的指针,以学习自己使代码变得更好。

2 个答案:

答案 0 :(得分:3)

我认为以下方法可行。基本上,我生成一个商列表,然后沿列表分配1单位的余数,直到将其完全消耗为止。

let integerBuckets total divider =
    let rem = total % divider
    let quo = total / divider
    let dividerList = [1..divider]
    [ for _ in dividerList do yield quo ]  //create list of quotients
    |> List.map2 (+) [for i in dividerList do if i <= rem then 1 else 0] //distribuite remainder

编辑:

上述功能可以总结如下:

let integerBuckets2 total divider =
    let rem,quo = total % divider,total / divider
    [ for i in [1..divider] do yield if i <= rem then quo + 1 else quo ]

答案 1 :(得分:0)

我建议您针对此问题采取更加面向数据的方法,以拆分作业进行处理。如果将要存储的项目存储在数组中,则可以使用数组函数对其进行操作。以下是一些可能的方法:

let chunkByChunkCount array chunkCount =
    let chunkSize = 
        (float (Array.length array) / float chunkCount)
        |> ceil
        |> int
    array |> Array.chunkBySize chunkSize

chunkByChunkCount [| 1 .. 15 |] 4
// [|[|1; 2; 3; 4|]; [|5; 6; 7; 8|]; [|9; 10; 11; 12|]; [|13; 14; 15|]|]



let dealIntoChunks array chunkCount =
    array
    |> Array.indexed
    |> Array.groupBy (fun (i, _) -> i % chunkCount)
    |> Array.map snd
    |> Array.map (Array.map snd)

dealIntoChunks [| 1 .. 15 |] 4
// [|[|1; 5; 9; 13|]; [|2; 6; 10; 14|]; [|3; 7; 11; 15|]; [|4; 8; 12|]|]