从地图中选择随机元素,使用非均匀分布

时间:2015-12-18 18:12:37

标签: haskell

我有一张地图m(使用import Data.Map),我想从中随机选择两个元素。到目前为止,我已经在GHCI中尝试了这个(它不起作用):

> :module System.Random
> -- define my map in "m", not important here
> let myrand a = getStdRandom $ randomR (0, a - 1)
> elemAt (myrand (size m)) m

我收到错误:Couldn't match expected type 'Int' with actual type 'IO Int'

首先,问题是,如何才能完成这项工作(我可以将IO Int转换为Int吗?)?最终我想要一个函数从地图中提取两个不同的值。

并且,第二个问题,我如何使用"较小的键"更有可能被选中?现在,如果我的代码有效,它只会选择一个具有统一分布的元素。我想要一个简单的说法"元素A,键低于元素B,被选中的机会更高"。我不知道如何继续这里,我试着看some documentation,但我不知道如何做到这一点(或者它对我来说是否有用)。

1 个答案:

答案 0 :(得分:4)

如果您想根据MapMap的位置选择Map的元素,首先转换为列表会更容易,因为import qualified Data.Map as M import Control.Monad.Random (fromList, MonadRandom) sampleAscending :: (MonadRandom m, Ord k) => M.Map k a -> m a sampleAscending m = fromList $ zip (map snd $ M.toAscList m) [l,l-1..] where l = fromIntegral $ M.size m 是无序容器

[l,l-1..]

由于您没有指定哪个分发,我只选择了一些简单的(fromList)。 MonadRandom m => [(a, Rational)] -> m a函数的类型为MonadRandom。候选元素中输入列表中元组的第一个元素,元组的第二个元素是该项发生的概率。 import Control.Monad import Text.Printf testSample :: (Eq a, Show a) => [a] -> IO () testSample strIn = do let m0 = M.fromList $ zip [1..] strIn len = 10000 :: Float str <- replicateM (round len) (sampleAscending m0) forM_ strIn $ \c -> printf "%s occured with probability %f\n" (show c) ((fromIntegral.length.filter(==c)$ str)/len) 界面会为您处理剩下的事情!

为了说服你这确实有用,这里有一点测试功能:

>testSample "abc"
'a' occured with probability 0.5044
'b' occured with probability 0.3281
'c' occured with probability 0.1675

>testSample "abcdefg"
'a' occured with probability 0.2473
'b' occured with probability 0.2192
'c' occured with probability 0.1814
'd' occured with probability 0.1339
'e' occured with probability 0.1112
'f' occured with probability 0.0687
'g' occured with probability 0.0383

let image = UIImageView(image: UIImage(named: "img.jpg"))
self.settingsTableView.backgroundView = image
self.settingsTableView.backgroundView?.frame = CGRectZero
self.settingsTableView.backgroundView?.contentMode = UIViewContentMode.ScaleAspectFit