2013-08-07 39 views
2

我開始從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搜索後一直無法找到它,所以我想我會在這裏問。這是可用的還是它是我必須實現自己的功能?謝謝!

回答

1

基於在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.ApplicativeliftM2 (:) (return val) (sample (ct-1) (delete val xs))

雖然使用delete對列表元素的類型會產生Eq約束,所以如果您需要避免這種情況,您必須在索引處拆分/合併。

+0

這很好,只是我想要的。我有點新,所以你可以解釋樣本n方法的最後一行嗎?另外,你爲什麼要做'idx < - randomRIO(0,l)'而不是'let idx = ...'? –

+0

它看起來像遞歸調用列表中剛刪除最後一個選定值的樣本?一旦它下降到零,它返回空列表'[]',結束這個過程。 –

+1

作爲返回純值的函數的結果綁定純值時使用let。作爲單值計算的結果,綁定純值時使用< - 。 –

2

您可以使用random.shuffle軟件包,該軟件包帶有shuffle'函數。但你需要一個隨機生成器。

您還可以查看有關Haskell的維基進一步解釋:http://www.haskell.org/haskellwiki/Random_shuffle

一旦你的列表洗牌,你可以在它take n元素。

+1

不使用'shuffle'功能。實際產生randoms列表的工作是由'shuffleM'(或'shuffle'')完成的,可能比你自己做得更好。 – muhmuhten

+0

我其實在想着'shuffle''。 – Nicolas

0

代碼:

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,確保它在列表的範圍內。然後分割列表並返回該數字,從而從列表中刪除它,然後遞歸直到不再需要數字。

+0

他也可以使用MonadRandom(「State」的專長)中隨機特定的monad中的一個,例如Rand。 –

+0

好吧,如果它被重寫爲'getRandom'而不是randomIO。 'getRandomR(0,length xs-1)'? – muhmuhten

+1

@sreservoir:實際上也有一個'randomRIO',所以功能非常相似。對於IO情況,代碼將類似於'sample xs =(map(xs !!)。take len)\'fmap \'replicateM len randomRIO其中len = length xs' –

相關問題