簡體   English   中英

使用cons(::)而不是concat(@)構建列表時F#折疊

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

我有以下功能,它做我想要的。 但是使用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., []) 

chgLstAndLast返回最后生成的結果值和列表:

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

我想以三種方式改進上述內容。

  1. 使用con(::)而不是concat(@)
  2. 將列表累積從myFunc移動到List.fold操作
  3. 確保結果列表順序保持與上面相同(即最后結果位於列表末尾而不是頭部)

例如,我想寫一個像這樣的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

但是當我這樣做時,我沒有看到如何在折疊功能中使用(::)缺點。

如果我沒有理解你的代碼,你想要做什么是fold ,同時保持所有的中間結果。 這幾乎就是List.scan作用; 它也返回初始狀態。

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

為了解釋一下這段代碼:首先我聲明一個內部函數,使代碼對外部世界更清晰(假設其他代碼不需要myFunc ),然后我使用scanfold獲取所有中間結果,是一種內置的方式來做你的折疊+累加器技巧。
最后一個值是通過reduce技巧獲得的,因為沒有內置的“last of list”函數,並且中間結果是處理數據的第二部分,除了第一個元素是初始狀態。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM