如何在OCAML中跳过带有List.Map的术语?

时间:2010-07-08 09:09:19

标签: ocaml

假设我有一些这样的代码:

List.map (fun e -> if (e <> 1) then e + 1 else (*add nothing to the list*))

有办法做到这一点吗?如果是这样,怎么样?

如果项目符合某些条件,我想要操纵该项目,如果不匹配则忽略它。因此,List.filter似乎不是解决方案。

6 个答案:

答案 0 :(得分:12)

SML有一个函数mapPartial,它正是这样做的。遗憾的是,OCaml中不存在此功能。但是你可以这样轻松地自己定义:

let map_partial f xs =
  let prepend_option x xs = match x with
  | None -> xs
  | Some x -> x :: xs in
  List.rev (List.fold_left (fun acc x -> prepend_option (f x) acc) [] xs)

用法:

map_partial (fun x -> if x <> 1 then Some (x+1) else None) [0;1;2;3]

将返回[1;3;4]

或者您可以使用filter_map from extlib作为ygrek指出。

答案 1 :(得分:7)

BatteriesExtlib都提供了等效的mapPartial:他们的扩展List模块提供filter_map类型的('a -> 'b option) -> 'a list -> 'b list函数,允许地图功能也选择项目。

答案 2 :(得分:5)

另一种解决方案是直接使用foldl

let f e l = if (e <> 1) 
            then (e + 1)::l 
            else l
in List.fold_left f [] list  

但我的偏好是filter_map作为Michael E

答案 3 :(得分:4)

或者,您可以过滤列表,然后在结果列表中应用地图,如下所示:

let map_bis predicate map_function lst =
    List.map map_function (List.filter predicate lst);;

# val map_bis : ('a -> bool) -> ('a -> 'b) -> 'a list -> 'b list = <fun>

用法:

# map_bis (fun e -> e<>1) (fun e -> e+1) [0;1;2;3];;
- : int list = [1; 3; 4]

答案 4 :(得分:1)

如果你想保留它们,你也可以将值映射到单例列表,如果不存在,你也可以将它们映射到空列表,然后将结果连接起来。

List.concat (List.map (fun e -> if (e <> 1) then [e + 1] else []) my_list)

答案 5 :(得分:0)

使用

let rec process = function
  | 1 :: t -> process t
  | h :: t -> (h + 1) :: (process t)
  | []     -> []

或尾递归

let process = 
  let rec f acc = function
    | 1 :: t -> f acc t
    | h :: t -> f ((h + 1) :: acc) t
    | []     -> List.rev acc in
  f []

或具有标准功能的组合

let process l = 
  l |> List.filter ((<>)1)
    |> List.map ((+)1)