Случайный элемент массива в F # - PullRequest
1 голос
/ 09 января 2011

Я пытаюсь изучить F # и боюсь, что я не понимаю что-то так, как следовало бы.

Я пытаюсь воссоздать функциональность книги, которая мне больше нравится (Творческое ругательство от Рояль и Панарезе).

В двух словах, у вас есть два отдельных списка слов, из которых можно выбрать два случайных слова, в результате чего получается странная фраза.Достаточно просто?

Вот что у меня есть:


#light

open System
open System.IO

let getWordList file =
  File.ReadAllLines( file )

let getRandArrElement (arr : string[]) =
  let rnd = Random( 0 )
  arr |> Seq.nth (rnd.Next arr.Length)

let wordList1 = getWordList "words1.txt"
let wordList2 = getWordList "words2.txt"

let word1 = getRandArrElement wordList1
let word2 = getRandArrElement wordList2

printf "%s %s" word1 word2

Это тоже работает.За исключением того, что он возвращает одну и ту же фразу каждый раз при запуске.

У меня такое ощущение, что он вычисляет одно случайное значение на один вызов getRandArrElement во время компиляции, а затем использует это значение в качестве значения THE(что я считаю странным, но что я знаю?).

Что не так с моей логикой, и как мне ее исправить?

Ответы [ 2 ]

10 голосов
/ 09 января 2011

Ваша проблема здесь:

let getRandArrElement (arr : string[]) =
  let rnd = Random( 0 )
  arr |> Seq.nth (rnd.Next arr.Length

Random числа на самом деле не случайны.Они принимают начальное значение, вычисляют случайное число от 0.0 до 1.0;это новое значение используется в качестве следующего семени.Другими словами, Random я - чисто детерминированный, поэтому при посеве с одним и тем же значением снова и снова получается одна и та же выходная последовательность.каждый раз получая одно и то же случайное число.

Я предлагаю несколько улучшений:

  • использование let rnd = Random().Конструктор по умолчанию использует системные часы в качестве начального числа, так что вы получите другую последовательность.(По-прежнему возможно получить ту же последовательность. Системные часы имеют разрешение около 10 мс, поэтому построение двух Рандомов в этом интервале с высокой вероятностью приведет к засеву с одинаковым значением.

    Есливы используете let rnd = Random(0), даже если rnd находится за пределами вашей функции, вы будете получать одинаковые предложения в одном и том же порядке при каждом запуске вашей программы.

  • Вы можете перемещатьобъявление rnd вне вашей функции, чтобы вы не создавали его снова и снова. В качестве альтернативы вы можете написать это:

    let getRandArrElement =
        let rnd = Random()
        fun (arr : string[]) -> ...
    

    F # выполняет все значения без параметров при открытии модуля, поэтому rnd будет назначено сразу, а getRandArrElement будет присвоено значение fun (arr : string[]) -> ....

  • Используйте arr.[index] вместо arr |> Seq.nth (rnd.Next arr.Length). Это не только более кратко, но ион также O (1). Seq.nth обрабатывает его как последовательность, он перемещается по одному элементу за раз, пока не доберется до элемента, соответствующего данному индексу, делая операцию O(n).

Окончательный результат шоуБудет что-то вроде:

let getRandArrElement =
  let rnd = Random()
  fun (arr : string[]) -> arr.[rnd.Next(arr.Length)]
3 голосов
/ 09 января 2011

Вы используете новый Случайный с одним и тем же начальным числом каждый раз, это ожидаемое поведение - при повторном использовании одного и того же начального числа генерируется одна и та же серия чисел. Я бы предложил вам убрать объявление rnd из функции, которая решит вашу проблему:

let rnd = Random();

let getRandArrElement (arr : string[]) =
  arr |> Seq.nth (rnd.Next arr.Length)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...