如何在OCAML中用List.Map跳过一个词?

问题描述 投票:10回答:6

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

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

有什么方法可以做到这一点吗? 如果有,怎么做?

我希望既能操作符合某些标准的项,又能忽略不符合标准的项。 因此,List.filter似乎不是解决方案。

ocaml
6个回答
13
投票

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 从extlib 正如ygrek指出的那样。


7
投票

两者 蓄电池Extlib 相当于 mapPartial预期成绩:其延长的 List 模块提供一个 filter_map 类型的函数 ('a -> 'b option) -> 'a list -> 'b list,允许地图功能也选择项目。


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


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]

1
投票

如果你想保留值,你也可以将其映射到单人列表,如果你不想保留,也可以将其映射到空列表,然后将结果进行连接。

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

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) 
© www.soinside.com 2019 - 2024. All rights reserved.