从Haskell列表中抽取任意数量的数字

时间:2013-08-07 14:20:49

标签: haskell

我开始从Ruby背景学习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搜索后找不到它,所以我想我会在这里问。这是可用的还是我必须自己实现的功能?谢谢!

3 个答案:

答案 0 :(得分:2)

您可以使用带有shuffle'功能的random.shuffle包。但是你需要一个随机发生器。

您还可以查看有关haskell wiki的更多说明:http://www.haskell.org/haskellwiki/Random_shuffle

一旦您的列表被随机播放,您可以take n个元素。

答案 1 :(得分: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约束,因此如果需要避免,则必须在索引处进行拆分/合并。

答案 2 :(得分: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 monad中,尽管您可以生成随机种子然后将其传递给函数。此代码获取随机int,确保它在列表的边界内。然后拆分列表并返回该数字,从而将其从列表中删除,然后递归,直到不再需要数字为止。