我开始从 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 中可用,我希望获得相同的功能。经过一番谷歌搜索后我无法找到它,所以我想我会在这里问。这是可用的还是我必须自己实现的功能?谢谢!
我开始从 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 中可用,我希望获得相同的功能。经过一番谷歌搜索后我无法找到它,所以我想我会在这里问。这是可用的还是我必须自己实现的功能?谢谢!
您可以使用该random.shuffle
软件包,它带有一个shuffle'
功能。但是你需要一个随机生成器。
您还可以在 haskell wiki 上寻找进一步的解释:http ://www.haskell.org/haskellwiki/Random_shuffle
一旦你的列表被洗牌,你可以take n
它的元素。
基于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
限制,因此如果需要避免这种情况,则必须在索引处拆分/合并。
代码:
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 中,尽管您可以生成随机种子,然后将其传递给函数。这段代码得到一个随机整数,确保它在列表的范围内。然后拆分列表并返回该数字,从而将其从列表中删除,然后递归直到不再需要数字。