99 questions/Solutions/24

From HaskellWiki
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.

Lotto: Draw N different random numbers from the set 1..M.

import System.Random
diff_select :: Int -> Int -> IO [Int]
diff_select n to = diff_select' n [1..to]

diff_select' 0 _  = return []
diff_select' _ [] = error "too few elements to choose from"
diff_select' n xs = do r <- randomRIO (0,(length xs)-1)
                       let remaining = take r xs ++ drop (r+1) xs
                       rest <- diff_select' (n-1) remaining
                       return ((xs!!r) : rest)

The random numbers have to be distinct!

In order to use randomRIO here, we need import module System.Random.

As can be seen, having implemented problem 23, rnd_select, the solution is trivial.

diff_select n to = rnd_select [1..to] n

Alternative solution:

diffSelect :: Int -> Int -> IO [Int]
diffSelect n m = do
  gen <- getStdGen
  return . take n $ randomRs (1, m) gen

(Note that this doesn't really solve the problem, since it doesn't generate distinct numbers).

Using nub from Data.List:

diff_select :: Int -> Int -> StdGen -> [Int]
diff_select n m = take n . nub . randomRs (1, m)

Or without giving StdGen as argument and returning IO [Int]:

import System.Random
import Data.List
import Control.Applicative

diff_select :: Int -> Int -> IO [Int]
diff_select n m = take n . nub . randomRs (1, m) <$> getStdGen

Note: With the above solutions using nub, the function will not terminate if m < n. I suggest adding a guard to protect against this.