简体   繁体   English

使用cons(::)而不是concat(@)构建列表时F#折叠

[英]F# Fold while building a list using cons (::) as opposed to concat (@)

I have the following function which does what I want. 我有以下功能,它做我想要的。 But is uses the concat (@) operator which is O(n) as opposed to O(1) for the (::) operator 但是使用concat(@)运算符,它是O(n)而不是O(1)运算符

let myFunc s m cs =  
    let n = s * m
    let c = [n - s] // single element list
    (n,  cs @ c) // concat the new value to the accumulated list

let chgLstAndLast = 
    [0.99; 0.98; 1.02] 
    |> List.fold (fun (s, cs) m -> myFunc s m cs) (1., []) 

The chgLstAndLast returns the last value and list of the results generated: chgLstAndLast返回最后生成的结果值和列表:

val chgLstAndLast : float * float list = (0.989604, [-0.01; -0.0198; 0.019404])

I would like to improve the above in three ways. 我想以三种方式改进上述内容。

  1. Use con (::) rather than concat (@) 使用con(::)而不是concat(@)
  2. Move the list accumulation from the myFunc to the List.fold operation 将列表累积从myFunc移动到List.fold操作
  3. Make sure that the resulting list order remains the same as above (ie last result is at end of list as opposed to the head) 确保结果列表顺序保持与上面相同(即最后结果位于列表末尾而不是头部)

For example, I would like to write a myFunc like this 例如,我想写一个像这样的myFunc

let myFunc s m cs =  
    let n = s * m
    let c = n - s // single element, but not as list
    (n, c) // No concat here

But when I do, I don't see how to use (::) cons in the Fold function. 但是当我这样做时,我没有看到如何在折叠功能中使用(::)缺点。

If I understand your code correctly, what you want to do is a fold while keeping all intermediary results. 如果我没有理解你的代码,你想要做什么是fold ,同时保持所有的中间结果。 This is almost what List.scan does; 这几乎就是List.scan作用; it also returns the initial state. 它也返回初始状态。

let chgLstAndLast data =
    let inner s m =
        let n = s * m
        n, n - s
    let processedData = data |> List.scan (fun (s, _) n -> inner s n) (1.0, 1.0)
    let lastResult = processedData |> List.reduce (fun _ n -> n)
    let seq = processedData |> List.tail |> List.map snd
    lastResult, seq

To explain a bit more on this code: first I declare an inner function to make the code cleaner to the exterior world (assuming myFunc isn't needed by other code), then I use scan to get all intermediary results from a fold , which is a built-in way to do your fold + accumulator trick. 为了解释一下这段代码:首先我声明一个内部函数,使代码对外部世界更清晰(假设其他代码不需要myFunc ),然后我使用scanfold获取所有中间结果,是一种内置的方式来做你的折叠+累加器技巧。
The last value is obtained with a reduce trick since there's no built-in "last of list" function, and the intermediary results are the second parts of the processed data, except for the first element which is the initial state. 最后一个值是通过reduce技巧获得的,因为没有内置的“last of list”函数,并且中间结果是处理数据的第二部分,除了第一个元素是初始状态。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM