F# - 我怎样才能将一个整数分成(大部分相等的)比这更好的“桶”?
F# - How can I divide an integer into (mostly equal) ‘buckets’ better than this?
我有一个整数,我想将其分成大小尽可能相等的整数“桶”列表。
一些例子:
- 用 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 循环中的数学;这么容易出错and/or一不小心改了。但我不确定的不只是数学部分。
任何人都可以给我一些关于如何将其“整理”成更易于阅读的更好的 F# 的指示吗?
我不是在要求某人提供更好的代码片段,而是在寻求我应该关注的领域的指示,以便自己学习使代码变得更好。
我认为下面的方法可行。基本上,我生成一个商列表,然后将余数的 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] //distribute 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 ]
我建议您采用更面向数据的方法来解决拆分作业进行处理的问题。如果将要处理的项目存储在数组中,则可以使用数组函数来操作它们。以下是一些可行的方法:
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|]|]
我有一个整数,我想将其分成大小尽可能相等的整数“桶”列表。 一些例子:
- 用 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 循环中的数学;这么容易出错and/or一不小心改了。但我不确定的不只是数学部分。
任何人都可以给我一些关于如何将其“整理”成更易于阅读的更好的 F# 的指示吗?
我不是在要求某人提供更好的代码片段,而是在寻求我应该关注的领域的指示,以便自己学习使代码变得更好。
我认为下面的方法可行。基本上,我生成一个商列表,然后将余数的 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] //distribute 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 ]
我建议您采用更面向数据的方法来解决拆分作业进行处理的问题。如果将要处理的项目存储在数组中,则可以使用数组函数来操作它们。以下是一些可行的方法:
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|]|]