【问题标题】:Merging two lists in F#在 F# 中合并两个列表
【发布时间】:2015-02-24 00:16:12
【问题描述】:

我编写了这个将两个列表合并在一起的函数,但由于我对函数式编程相当陌生,我想知道是否有更好(更简单)的方法来做到这一点?

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"; “乙”; “C”; “d”],我正在还原列表以保持原始顺序。我以为我可以使用 List.foldBack(并删除 List.rev)来实现相同的目标,但它会导致错误:

类型不匹配。期待一个 '一个
但给定一个 '列表
当统一 ''a' 和 ''a list' 时,结果类型将是无限的

为什么在使用 foldBack 时会有所不同?

【问题讨论】:

  • 对于foldBack,检查文件夹中参数的顺序,应该是(fun elem acc -> ...)

标签: f#


【解决方案1】:

你可以使用类似下面的东西

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

请注意,这将保留顺序并删除所有重复项。

在 F# 4.0 中,这将被简化为

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

【讨论】:

  • 是否可以包含过滤功能?如果我有一个记录列表并想按其中一个属性进行比较?
  • 根据您想要过滤的方式,您可以将结果通过管道传输到 List.filter,或使用 Seq.distinctBy
【解决方案2】:

如果我想以与您的原始版本类似的方式编写此代码(使用fold),那么我要做的主要更改是将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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-06-16
    • 2012-03-20
    • 2011-04-25
    • 2021-10-07
    • 2014-08-30
    相关资源
    最近更新 更多