【问题标题】:When building list recursively, how to use created elements of list at the head?递归构建列表时,如何在头部使用已创建的列表元素?
【发布时间】:2012-06-05 13:22:39
【问题描述】:

我正在尝试在 F# 中编写一个引导算法,该算法采用一组输入并创建一个输出列表。如果我只需要使用前一个元素,那么使用递归很简单:

let buildElement head previous =
    // do something to create new float 
    1.0

let buildList inputs =
    let rec bootstrap elements previous = 

        let addElement head tail =
            let newElement = buildElement head previous
            newElement :: bootstrap tail newElement   

        match inputs with
            | []    -> []
            | h::t  -> addElement h t
    bootstrap inputs 1.0

但是,如果我想使用以前创建的元素(例如,我想将新值的平均值作为以前的值传递),我如何在内部函数中访问它们?我是否在外部函数中创建一个集合并在内部函数中填充它?如果是这样,我需要使其可变吗?

【问题讨论】:

  • 请注意,如果您切换buildElement 的参数,您的buildList 函数只能定义为List.scan buildElement 1.0 inputs
  • 这是一个公平的观点。我只是想弄清楚原理,这只是实际代码的精简版。

标签: recursion f# functional-programming


【解决方案1】:

如果是平均函数,您可以传递部分总和和处理项目的数量并使用它来计算平均值。

对于一般解决方案,您可以将先前结果列表作为参数,使用 :: 将下一个结果添加到它的前面,并在完成后反转整个过程。这具有使您的函数尾递归的额外好处。

【讨论】:

    【解决方案2】:

    如果您需要根据过去值的一些信息计算新值,您基本上会做与现在所做的相同的事情 - 而不是在 previous 中传递最后一个值 previous参数可以是您在执行过程中重新计算的过去值的列表。

    我认为不知道具体示例很难给出更好的答案。但是,假设您想计算浮动平均值 - 为此,您需要计数和所有先前值的总和。您可以使用递归直接对其进行编码,也可以使用Seq.scan:

    [ 1.0 .. 100.0 ] 
    |> Seq.scan (fun (count, sum) elem -> count + 1, sum + elem) (0, 0.0)
    |> Seq.map (fun (count, sum) -> sum / float count)
    

    【讨论】:

    • 感谢 Tomas,我想我现在有了。完成后我会将 fssnip 的实际代码放上去,我认为这将是 niec。
    【解决方案3】:

    如果我想使用之前创建的元素(例如,我想传入新值的平均值作为之前的值),我如何在内部函数中访问它们?

    这是foldscan(前缀折叠)。您将列表映射或折叠为新值,并累积影响结果的值。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-08
      • 1970-01-01
      • 2020-02-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-08
      相关资源
      最近更新 更多