我開始從Ruby背景學習Haskell。我期待能夠從列表中得到物品任意數量的:從Haskell列表中抽樣任意數量的數字
sample [1,2,3,4,5,6,7,8,9,10]
=> 7
sample 3 [1,2,3,4,5,6,7,8,9,10]
=> [4,2,9]
這是在Ruby中可用的,我希望能得到相同的功能。 Google搜索後一直無法找到它,所以我想我會在這裏問。這是可用的還是它是我必須實現自己的功能?謝謝!
我開始從Ruby背景學習Haskell。我期待能夠從列表中得到物品任意數量的:從Haskell列表中抽樣任意數量的數字
sample [1,2,3,4,5,6,7,8,9,10]
=> 7
sample 3 [1,2,3,4,5,6,7,8,9,10]
=> [4,2,9]
這是在Ruby中可用的,我希望能得到相同的功能。 Google搜索後一直無法找到它,所以我想我會在這裏問。這是可用的還是它是我必須實現自己的功能?謝謝!
基於在http://ruby-doc.org/core-2.0/Array.html樣品,其中選擇n個隨機指數爲陣列的代碼,我想出了以下內容:
import System.Random
import Data.List
import Control.Applicative
sample1 xs = do
let l = length xs - 1
idx <- randomRIO (0, l)
return $ xs !! idx
sample 0 xs = return []
sample n xs = do
let l = min n (length xs)
val <- sample1 xs
(:) <$> (pure val) <*> (sample (l-1) (delete val xs))
或者,你可以使用Control.Monad
代替Control.Applicative
和liftM2 (:) (return val) (sample (ct-1) (delete val xs))
雖然使用delete
對列表元素的類型會產生Eq
約束,所以如果您需要避免這種情況,您必須在索引處拆分/合併。
您可以使用random.shuffle
軟件包,該軟件包帶有shuffle'
函數。但你需要一個隨機生成器。
您還可以查看有關Haskell的維基進一步解釋:http://www.haskell.org/haskellwiki/Random_shuffle
一旦你的列表洗牌,你可以在它take n
元素。
代碼:
import System.Random
sample :: Int -> [a] -> IO [a]
sample count lst = go count lst []
where go 0 _ acc = return acc
go count xs acc = do
rnd <- randomIO :: IO Int
let ind = rnd `rem` (length xs)
(beg, (r:rs)) = splitAt ind xs
go (count-1) (beg ++ rs) (r : acc)
由於隨機數生成不純你需要在IO單子,但你可以生成隨機種子,然後PAS對函數。此代碼獲取一個隨機int,確保它在列表的範圍內。然後分割列表並返回該數字,從而從列表中刪除它,然後遞歸直到不再需要數字。
他也可以使用MonadRandom(「State」的專長)中隨機特定的monad中的一個,例如Rand。 –
好吧,如果它被重寫爲'getRandom'而不是randomIO。 'getRandomR(0,length xs-1)'? – muhmuhten
@sreservoir:實際上也有一個'randomRIO',所以功能非常相似。對於IO情況,代碼將類似於'sample xs =(map(xs !!)。take len)\'fmap \'replicateM len randomRIO其中len = length xs' –
這很好,只是我想要的。我有點新,所以你可以解釋樣本n方法的最後一行嗎?另外,你爲什麼要做'idx < - randomRIO(0,l)'而不是'let idx = ...'? –
它看起來像遞歸調用列表中剛刪除最後一個選定值的樣本?一旦它下降到零,它返回空列表'[]',結束這個過程。 –
作爲返回純值的函數的結果綁定純值時使用let。作爲單值計算的結果,綁定純值時使用< - 。 –