开发者

How can I skip a term with List.Map in OCAML?

开发者 https://www.devze.com 2023-01-06 21:00 出处:网络
Suppose I have some code like this: List.map (fun e -> if (e <> 1) then e + 1 else (*add nothing to the list*))

Suppose I have some code like this:

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

Is there a way to do this? If so, how?

I want 开发者_如何学Goto both manipulate the item if it matches some criteria and ignore it if it does not. Thus List.filter wouldn't seem to be the solution.


SML has a function mapPartial which does exactly this. Sadly this function does not exist in OCaml. However you can easily define it yourself like this:

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)

Usage:

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

will return [1;3;4].

Or you can use filter_map from extlib as ygrek pointed out.


Both Batteries and Extlib provide an equivalent of mapPartial: their extended List module sprovide a filter_map function of the type ('a -> 'b option) -> 'a list -> 'b list, allowing the map function to select items as well.


Another solution would be to use directly a foldl :

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

But my preference is filter_map as Michael Ekstrand provided


Alternatively you can filter your list then apply the map on the resulted list as follows :

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>

Usage :

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


You can also map values to singleton lists if you want to keep them or empty lists if you don't, and then concat the results.

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


use

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

or tail recursive

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

or with a composition of standard functions

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


The OCaml standard library has had List.filter_map since 4.08. This can therefore now be written as:

List.filter_map (fun e -> if e <> 1 then Some (e + 1) else None)
0

精彩评论

暂无评论...
验证码 换一张
取 消