如何在 OCaml 中不使用 List.filter 过滤列表?

How do I filter a list without using List.filter in OCaml?

我必须编写一个函数,给定两个列表,它 return 是第一个元素的列表,其平方出现在第二个列表中(对不起我的英语)。我不能递归地做,我不能使用 List.filter。 这就是我所做的:

let lst1= [1;2;3;4;5];;
let lst2= [9;25;10;4];;

let filquadi lst1 lst2 =
  let aux = [] in 
  List.map(fun x -> if List.mem (x*x) lst2 then x::aux else []) lst1;;

它有效,但当数字不满足 if 语句时它也会打印 []:

filquadi lst1 lst2 ;;
- : int list list = [[]; [2]; [3]; []; [5]]

我怎样才能 return 一个数字列表而不是一个数字列表的列表?

- : int list = [2;3;5]

你可以用List.concat把东西放在最后:

List.concat (List.map ...)

作为旁注,aux 在您的代码中没有做任何有用的事情。它只是空列表的名称(因为 OCaml 变量是不可变的)。使用 [x] 而不是 x :: aux.

可能会更清楚

作为另一边的评论,这是一个听起来很奇怪的任务。通常禁止使用 List 模块中的函数的原因是鼓励您编写自己的递归解决方案(这确实具有教育意义)。我暂时看不出禁止使用递归的理由,但是以不同的方式组合 List 中的函数很有趣。

您的条件并没有说您不能使用 List.fold_leftList.rev,所以...

let filter lst1 lst2 =
  List.fold_left 
    (fun init x -> 
       if List.mem (x * x) lst2 then x::init 
       else init) 
    [] lst1 
  |> List.rev

我们从一个空列表开始,当我们折叠第一个列表时,仅当该元素出现在第二个列表中时才添加当前元素。因为这会导致列表与其原始顺序相反,所以我们随后将其反转。

如果您不应该使用递归,这在技术上是作弊,因为 List.fold_left 递归工作,但基本上任何使用列表的工作都是如此。重新实现 List 模块的功能将涉及大量递归,从重新实现 fold_leftfilter.

可以看出
let rec fold_left f init lst =
  match lst with
  | [] -> init
  | x::xs -> fold_left f (f init x) xs

let rec filter f lst =
  match lst with 
  | [] -> []
  | x::xs when f x -> x :: filter f xs
  | _::xs -> filter f xs