patternMinor
Write a function to extract a given number of randomly selected elements from a list
Viewed 0 times
numberelementsfunctionwriterandomlyselectedextractlistfromgiven
Problem
I'm going through the 99 Haskell problems and I have a few question about the solution I implemented for Problem 23.
It asks:
Extract a given number of randomly selected elements from a list.
This is the code I came up with:
It works, but I'm not sure this is idiomatic Haskell nor that it is the best way to address this problem.
None of the solutions in the Haskell wiki uses the
It asks:
Extract a given number of randomly selected elements from a list.
This is the code I came up with:
-- Extract a given number of randomly selected elements from a list.
import System.Random
randomFromList :: StdGen -> Int -> [a] -> ([a], StdGen)
randomFromList generator 0 _ = ([], generator)
randomFromList generator toDo xs =
let (nextInt, generator') = next generator
index = mod nextInt (length xs)
(otherNumbers, generator'') = randomFromList generator' (toDo -1) xs
in ((xs !! index) : otherNumbers, generator'')It works, but I'm not sure this is idiomatic Haskell nor that it is the best way to address this problem.
None of the solutions in the Haskell wiki uses the
let approach so I was wondering if it is discouraged for some reason.Solution
Your solution looks good to me, no reason to discourage using
Tip: if you make the type
Also, if the requirement is interpreted as selecting randomly without replacement, your version only needs slight modification (this also uses
See also this shuffle implementation for some attempt at optimisation. (You could potentially solve the random selection by something like
let as far as I know.Tip: if you make the type
randomFromList :: Int -> [a] -> StdGen -> ([a], StdGen), then you can call it like this: main = getStdGen >>= print . randomFromList 7 ['A'..'Z']Also, if the requirement is interpreted as selecting randomly without replacement, your version only needs slight modification (this also uses
randomR rather than mod):dropAt :: Int -> [a] -> [a]
dropAt k xs = take k xs ++ drop (k+1) xs
randomFromList :: Int -> [a] -> StdGen -> ([a], StdGen)
randomFromList 0 _ generator = ([], generator)
randomFromList _ [] generator = ([], generator)
randomFromList toDo xs generator =
let (index, generator') = randomR (0, length xs - 1) generator
(otherNumbers, generator'') = randomFromList (toDo -1) (dropAt index xs) generator'
in ((xs !! index) : otherNumbers, generator'')See also this shuffle implementation for some attempt at optimisation. (You could potentially solve the random selection by something like
take n . shuffle.)Code Snippets
dropAt :: Int -> [a] -> [a]
dropAt k xs = take k xs ++ drop (k+1) xs
randomFromList :: Int -> [a] -> StdGen -> ([a], StdGen)
randomFromList 0 _ generator = ([], generator)
randomFromList _ [] generator = ([], generator)
randomFromList toDo xs generator =
let (index, generator') = randomR (0, length xs - 1) generator
(otherNumbers, generator'') = randomFromList (toDo -1) (dropAt index xs) generator'
in ((xs !! index) : otherNumbers, generator'')Context
StackExchange Code Review Q#62910, answer score: 2
Revisions (0)
No revisions yet.