sizes :: StdGen -> Int -> Int -> [Int]
sizes g c 0 = []
sizes g c b = a : (sizes g' (c - a) (b - 1)) where
(a, g') = randomR (1, c - b) g
main = do
g <- newStdGen
print $ sizes g 100 10
我已经把这个问题归结为产生一些数字的随机数列表的问题。
此代码基本上有效,但数字似乎不均匀分布(例如[7,46,3,4,26,8,1,2,1,1]
)。
他们在开始时往往很大,然后最终变小。从代码中可以明显看出它的原因。
我想要的是像[8, 6, 10, 4, 15..]
这样的数字彼此并没有那么不同。
答案 0 :(得分:0)
我不太清楚你想做什么,但如果你想要在最小值和最大值之间进行统一分配,你可以使用randomRs
:
Prelude> :m +System.Random
Prelude System.Random> g <- newStdGen
Prelude System.Random> take 10 $ randomRs (10, 100) g
[48,93,21,50,84,57,25,80,68,18]
如果您希望这些随机数总和为特定数字,您基本上可以从左侧开始挑选,直到您足够接近。 inits
函数可以帮助您:
Prelude System.Random> :m +Data.List
Prelude System.Random Data.List> take 10 $ inits $ randomRs (10, 100) g
[[],[48],[48,93],[48,93,21],[48,93,21,50],[48,93,21,50,84],[48,93,21,50,84,57],
[48,93,21,50,84,57,25],[48,93,21,50,84,57,25,80],[48,93,21,50,84,57,25,80,68]]
而不是take 10
,你可以开始浏览这个列表列表,直到找到一个足够接近的列表。例如,您可以计算所有这些列表的总和:
Prelude System.Random Data.List> fmap sum $ take 10 $ inits $ randomRs (10, 100) g
[0,48,141,162,212,296,353,378,458,526]
所以,如果你的目标是500,你可以看到第九个总和是458,而第十个总和太高了。换句话说,前九个数字会让你达到458.你将如何达到500?
一个选项只是说,那么最后一个数字必须是500 - 458 = 42,但是我不确定分布是否完全统一,因为最后一个数字是确定性的。
另一个选择是保持生成随机数,直到你有一个完美契合的序列。
由于我不知道确切的要求,我不能建议哪种方式最好。
在上面的示例中,我使用fmap sum
来说明我的观点。这样做的问题是,通过这样做,你扔掉了生成总和的数字。据我所知,你实际上想要那些数字,所以你可能需要一个更复杂的左侧折叠来计算总和,同时还要记住产生它的数字。您可以使用foldl
或foldl'
。