【问题标题】:How to create a new list in a recursive F# function?如何在递归 F# 函数中创建新列表?
【发布时间】:2020-02-16 06:22:49
【问题描述】:

我正在创建一个递归函数,它将查看现有列表,并创建一个新列表但没有重复项。我正在删除现有列表的头部,并检查新列表以查看它是否包含该元素。如果没有,那么我添加它,因为我知道它不是重复的。

到目前为止,我有这个代码。

let newList = []
let rec filtered inputList = 
  match inputList with
    | [] -> []
    | h::t -> if List.contains h newList then filtered t else h::(filtered t)

我知道在我的 else 语句中我没有将该元素添加到 newList。有没有办法在使用 match 语句时在 if 语句中执行多行代码?我该如何解决这个问题?

【问题讨论】:

  • 如果您这样做是出于教育目的,请继续,但请注意 List.distinct 存在。

标签: list recursion functional-programming f#


【解决方案1】:

在函数式编程中,通常你不会附加到一个列表,而是在递归函数中传递它,然后像这样在最后返回它。

let distinct list =
    let rec filtered inputList outputList = 
      match inputList with
        | [] -> outputList
        | h::t -> if List.contains h outputList then (filtered t outputList) else (filtered t (h::outputList))

    filtered list []

printf "%A" (distinct [1; 2; 2; 3]) // [3; 2; 1]

我尝试尽可能多地保留您的原始代码,以使差异更加明显。基本上,您从一个空列表开始递归函数,最后它返回包含唯一元素的列表。

现在这更像是一个风格问题,但我也会像这样打破 if 分开

let distinct list =
    let rec filtered inputList outputList = 
      match inputList with
        | [] -> outputList
        | h::t when List.contains h outputList -> filtered t outputList
        | h::t -> filtered t (h::outputList)

    filtered list []

printf "%A" (distinct [1; 2; 2; 3]) // [3; 2; 1]

【讨论】:

    【解决方案2】:

    dee-see 的解决方案有一个很好的特性,那就是它是尾递归的。这意味着它可以轻松处理非常大的列表。

    但是,如果您是函数式编程的新手,那么从更简单的版本开始可能会更容易,它接受输入列表并直接返回输出列表作为结果。

    这实际上与您所拥有的非常接近。你需要实现的逻辑是:

    • 如果列表的其余部分有元素,则跳过它
    • 如果该元素不在列表的其余部分,我们追加它

    为此,您不需要newList。您可以简单地检查List.contains h t,因为这样可以确保您只返回每个重复元素的最后一次出现:

    let rec filtered inputList = 
      match inputList with
      | [] -> []
      | h::t -> if List.contains h t then filtered t else h::(filtered t)
    
    filtered [1;2;3;2;3;4;5;4;1]
    

    与您的功能的唯一区别在于条件。 dee-see 的解决方案更复杂,但它达到了相同的结果。与其他答案一样,您可以使用when 更优雅地做到这一点:

    let rec filtered inputList = 
      match inputList with
      | [] -> []
      | h::t when List.contains h t -> filtered t 
      | h::t -> h::(filtered t)
    

    【讨论】:

      【解决方案3】:

      另一种方式:

      let rec distinct = function
          | []   -> []
          | h::t -> h :: distinct (List.filter ((<>) h) t)
      

      【讨论】:

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