2013-08-07 3 views
2

Я начинаю изучать 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, и я надеюсь получить ту же функциональность. Я не смог найти его после некоторых поисковых запросов, поэтому я решил, что попрошу здесь. Является ли это доступным или это функция, которую я должен был бы реализовать самостоятельно? Благодаря!

ответ

1

на основе кода в http://ruby-doc.org/core-2.0/Array.html для образца, который выбирает п случайные индексы в массиве, я придумал следующее:

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 на тип элементов списка, поэтому вам нужно будет разделить/слить индекс, если вам нужно этого избежать.

+0

это здорово, работает именно так, как я хочу. Я несколько новичок, так что вы могли бы объяснить последнюю строку в методе sample n? Кроме того, почему вы делаете 'idx <- randomRIO (0, l)' вместо 'let idx = ...'? –

+0

похоже, что он рекурсивно вызывает образец в списке, который только что удалил последнее выбранное значение? и как только он опустится до нуля, он возвращает пустой список '[]', завершая процесс. –

+1

Используйте let при связывании чистого значения в результате функции, возвращающей чистые значения.Используйте <- при связывании чистого значения в результате монадического вычисления. –

2

Вы можете использовать пакет random.shuffle, который поставляется с функцией shuffle'. Но вам нужен генератор случайных чисел.

Вы можете также искать дополнительные пояснения на Haskell вики: http://www.haskell.org/haskellwiki/Random_shuffle

После того, как ваш список перемешивается, вы можете take n ее элементы.

+1

не используйте функцию 'shuffle'. работа над созданием списка randoms выполняется 'shuffleM' (или' shuffle''), вероятно, лучше, чем вы могли бы сделать сами. – muhmuhten

+0

Я действительно думал о «перетасовке». – Nicolas

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, хотя вы могли бы генерировать случайные семена, а затем па, что функции. Этот код получает случайный int, поэтому он находится внутри границ списка. Затем разбивает список и возвращает это число, удаляя его из списка, а затем рекурсируя, пока не потребуется больше чисел.

+0

Он также может использовать одну из случайных монад, таких как «Rand» из MonadRandom (специализация «State»). –

+0

ну, если бы это было переписано 'getRandom' вместо randomIO. 'getRandomR (0, length xs-1)'? – muhmuhten

+1

@sreservoir: На самом деле есть 'randomRIO', поэтому функции очень похожи. Для случая ввода-вывода код будет выглядеть как «sample xs = (map (xs !!). Take len) \' fmap \ 'replicateM len randomRIO где len = length xs' –

Смежные вопросы