2015-02-23 63 views
0

我寫了這個函數,它將兩個列表合併在一起,但是因爲我對函數式編程相當陌生,所以我想知道是否有更好的(更簡單)的方法來實現它?合併F#中的兩個列表

let a = ["a"; "b"; "c"] 
let b = ["d"; "b"; "a"] 

let merge a b = 
    // take all a and add b 
    List.fold (fun acc elem -> 
        let alreadyContains = acc |> List.exists (fun item -> item = elem) 
        if alreadyContains = true then 
         acc 
        else 
         elem :: acc |> List.rev 
        ) b a     

let test = merge a b 

預期結果是:[「a」; 「B」; 「C」; 「d」],我正在恢復列表以保持原始順序。我認爲我可以使用List.foldBack(並刪除List.rev)來實現相同的效果,但會導致錯誤:

類型不匹配。期待 「一個
但給予 ‘列表
統一‘’A’和'名單」

爲什麼會出現使用折返當差時產生的類型將是無限的?

+0

對於foldBack,請檢查文件夾中參數的順序,它應該是(fun elem acc - > ...) – 2015-02-23 16:09:13

回答

2

,然後我會做的主要變化是將List.rev外的函數(!每一次你調用List.rev添加新的元素,這是不對的,如果你要添加偶數元素)的

所以,非常類似你這樣的解決辦法是:

let merge a b = 
    (b, a) 
    ||> List.fold (fun acc elem -> 
     let alreadyContains = acc |> List.exists (fun item -> item = elem) 
     if alreadyContains = true then acc 
     else elem :: acc) 
    |> List.rev 

這使用雙管道運算符||>將兩個參數傳遞給fold函數(這不是必需的,但我覺得它更好一些),然後將結果傳遞給List.rev

3

你可以使用類似下面的

let merge a b = 
    a @ b 
    |> Seq.distinct 
    |> List.ofSeq 

注意,這將會維持秩序,並刪除任何重複。

在F#4.0如果我想在某種程度上類似於(使用fold)你原來的版本寫這本將簡化爲

let merge a b = a @ b |> List.distinct 
+0

是否可以包含濾鏡功能?如果我有一個記錄列表並想通過其中一個屬性進行比較? – Jammes 2015-02-23 16:21:55

+0

根據你想要過濾的方式,你可以將結果傳遞給List.filter,或者使用Seq.distinctBy – 2015-02-23 20:07:04