使用递归和模式匹配从列表中删除元素

时间:2018-09-06 22:55:57

标签: recursion f# pattern-matching

在F#中使用递归,我应该编写一个递归函数以从列表l中删除整数n。 该函数接受int和iList并返回一个iList(它是整数列表)

这是我到目前为止所拥有的:

let rec remove n l match l with | E -> failwith "Empty List" | L(h,E) -> if (h=n) then 0 else h | L(h,t) -> if (h=n) then remove n t else h + remove n t

在上面的代码中,我进行了设置,以便在从列表中排除给定的整数n之后,返回列表中元素的总和而不是列表中的实际元素。

在排除给定的整数n之后,我需要帮助返回列表的其余元素。

2 个答案:

答案 0 :(得分:2)

您可以使用累加器参数(以下代码中的acc)来做到这一点。 acc参数用于将上一次调用的结果传递给递归函数,从而构建最终结果。这是函数编程中的常见范例。在这种情况下,我们从一个空列表开始acc并向其中添加元素,但是当它与x匹配时跳过。

let rec remove x l acc =
    match l with
    | [] -> acc
    | h::t when x = h ->  List.append acc t
    | h::t -> remove x t (List.append acc [h])

像这样使用它:

remove 1 [1;2;3] []

另一种方法是使用List.collect

let remove_use_collect x l =
    let helper y =
        if x = y then [] else [y]
    List.collect helper l

但是,我认为了解第一种方法和如何使用累加器参数很重要,因为它在函数编程中很常见,在这种情况下您无法修改值。您会发现很多“列表”模块功能都是在某个地方使用累加器实现的。

答案 1 :(得分:1)

来自sashang的答案假定内置的F#list类型。由于该问题似乎在案例EL中使用了自定义类型,因此这里给出的答案完全不依赖于List模块或类型。它也不会将累加器公开为顶级参数,因此调用者不必担心传递初始值:

type ilist = E | L of (int * ilist)

let remove value list =
    let rec remove value acc = function
    | E -> acc
    | L (head, tail) when head = value -> tail |> remove value acc
    | L (head, tail) -> tail |> remove value (L (head, acc))

    list |> remove value E

重要的是,此功能将有效地反转列表的顺序。如果需要保留列表的顺序,则可以增强功能以​​支持该要求。