【问题标题】:Generating unique random number生成唯一的随机数
【发布时间】:2018-12-25 13:13:36
【问题描述】:

我有一个应用程序,我想在读取 json 后三次在 init 上生成 5 个唯一数字的列表。所以基本上我想得到类似 [31, 59, 62, 72, 2, 16, 2, 38, 94, 15, 55, 46, 83, 2, 10] 的东西。我的挑战是我是函数式编程和榆树的新手,我有点迷茫。所以我知道 Random.generate 需要一个 msg 和一个生成器并返回一个 cmd 消息,它主要用于更新函数,但这不是我需要的,因为它是一个辅助函数,不需要与客户端通信.我认为它可以在init中使用,但我不知道如何。同样,我的函数是递归的,我不知道如何将这个逻辑与 Random.generate 递归地应用。

我知道我的代码不起作用,我已经尝试过了,因为 Random.int 不会生成随机数,而是生成的一种类型,但我仍然不知道如何应用它来获得我想要的。

recursion : Int -> List a -> List number
recursion a b =
  if List.length b > 5
      then b
  else 
      let 
          rand = Random.int 0 a
      in
          if(List.member rand b)
              then recursion a b
          else
              recursion a (rand :: b)

可以通过以下方式调用:

recursion 50 []

我想生成一个包含 5 个唯一随机 3 次的列表/数组。

【问题讨论】:

    标签: elm


    【解决方案1】:

    很好的问题。这里有两个部分: - 生成随机数,以及 - 把这一切都连接起来

    对于前者,您需要 Random 库,稍作检查就会发现类似

    get15Randoms = Random.generate OnRandomNumbers <| Random.list 5 (int 0 100)
    

    这有 Cmd Msg 类型 - 这是一个异步操作,将返回一个 Msg。

    将其连接起来将是一系列阶段。您指的是在“init”中执行此操作,但这不是 Elm 在这里为您工作的方式。在 init 函数中,您可以开始您的 json 请求。然后你需要类似的东西

    init = ( initModel
           , Http.get {url =..., expect = Http.expectJson OnJson yourDecoder} 
           )
    
    update msg model = 
        case msg of 
            OnJson (Ok data) ->
                -- attach json
                ( {model | data = data }, get15Randoms )
            OnRandomNumbers ints ->
                ( { model | ints = ints }, Cmd.none )
    

    换句话说,一旦 json 返回,您可以附加它,并使用该更新迭代来启动您的随机数请求,然后在后续迭代中捕获结果

    【讨论】:

    • 我不确定我是否理解您是如何将其连接起来的,但我知道大致的想法。例如,OnJson 是如何被触发的,我最终使用了 NoOp,这在我的回复中可以看出,这肯定是由您的回复引起的。如果您对诸如使用传递给 OnRandomNumbers 的整数之类的事情进行更多说明,我将很乐意接受您的回答,因为我也无法弄清楚。
    • 我在答案中添加了更多内容 - 看看 init 将如何触发 json 请求,并将返回标记为 OnJson 的 Elm。当它到达时,您可以使用它来触发随机数请求
    【解决方案2】:

    随机数生成是一种副作用,因为它在定义上是不可预测的,这意味着它的输出并不完全由它的输入决定。在 Elm 中,所有副作用都通过更新函数,因为如果在任何地方都允许副作用,则无法保证代码的任何部分都是纯粹的和可预测的。事情可能会随机开始表现不同,而且很难弄清楚为什么随机输入可以发生在任何地方。

    也就是说,init 是一个允许副作用的地方,因为还没有任何状态。但由于大多数副作用不是立竿见影的,而且您很可能希望显示一些 UI 来指示您的应用程序正在加载,我假设 API 并没有复杂到允许如此罕见的用例。特别是因为您可以使用几种解决方法:

    解决方法 1 - 空表示

    由于您使用列表来包含随机数,因此您可能只使用一个空列表来表示您尚未收到这些数字。否则使用Maybe 或自定义类型。这可能有点麻烦,因为您每次使用时都必须处理空箱,但根据您的用例,它可能是可以接受的。

    解决方法 2 - 标志

    Elm 允许在初始化时从外部向您的程序发送数据,并将其传递给您的init 函数。这种机制称为flags。您可以使用它在 JavaScript 中生成数字,然后将其作为参数发送。

    在您的index.html 中,您可以输入:

    var app = Elm.Main.init({
      node: document.getElementById('elm'),
      flags: Array.from({length: 15}, () => Math.floor(Math.random() * 50))
    });
    

    init 中,您接受数字作为普通参数:

    init : List number -> Model
    init numbers = 
        { myNumbers = numbes
        , ...
        }
    

    【讨论】:

    • 这帮助我了解并了解事物在 elm 中的流程,但如果可能的话,我不想在 js 中做任何事情,因为这会破坏尝试在 elm 中构建东西的目的。
    【解决方案3】:

    我想用 @Simon-h 的回答激励我最终做的事情来回应。我有一个 Msg 类型 RndGen Int,由于 update 是一个函数,我决定在 update 函数的帮助下递归调用 RndGen,并在我得到所需的随机数时将其标记出来。

    update msg model =
     case msg of
       NoOp ->
         (model, get15Randoms)
       RndGen rndGen ->
         if List.length (model.questions) < 15
           then
             if List.member rndGen model.questions
               then
                 (model, get15Randoms)
             else
               ({model | questions = rndGen :: model.questions  }, get15Randoms)
         else
           (model, Cmd.none)
    

    get15Randoms = 
      Random.generate RndGen (Random.int 0 100)
    

    在初始化时

    init questions =
      (Model (getQuestions questions) 1 True [] False "", get15Randoms)
    

    我想知道我的想法是否符合 elm 社区的期望。

    【讨论】:

      猜你喜欢
      • 2020-05-27
      • 1970-01-01
      • 1970-01-01
      • 2018-05-03
      • 2017-09-24
      • 2013-03-13
      • 2014-04-26
      相关资源
      最近更新 更多