Reputation: 4202
I'm starting to learn Haskell from a Ruby background. I'm looking to be able to get an arbitrary number of items from a list:
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]
This is available in Ruby and I'm hoping to get the same functionality. I haven't been able to find it after some googling, so I figured I would ask here. Is this available or is it a function I would have to implement myself? Thanks!
Upvotes: 2
Views: 752
Reputation: 4984
Based on the code at http://ruby-doc.org/core-2.0/Array.html for sample, which chooses n random indices into the array, I came up with the following:
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))
Alternatively, you could use Control.Monad
instead of Control.Applicative
and liftM2 (:) (return val) (sample (ct-1) (delete val xs))
Using delete
does incur an Eq
constraint on the type of the list elements, though, so you would have to split/merge at the index if you needed to avoid that.
Upvotes: 1
Reputation: 24759
You can use the random.shuffle
package, which comes with a shuffle'
function. But you need a Random generator.
You can also look for further explanation on the haskell wiki: http://www.haskell.org/haskellwiki/Random_shuffle
Once your list is shuffled, you can take n
elements of it.
Upvotes: 2
Reputation: 3766
Code:
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)
Since random number generation is impure you need to be in the IO monad, although you could generate a random seed and then pas that to the function. This code gets a random int, makes sure it is inside the bounds of the list. Then splits the list and returns that number thus removing it from the list and then recursing until no more numbers are needed.
Upvotes: 0