假设我有一些这样的代码:
List.map (fun e -> if (e <> 1) then e + 1 else (*add nothing to the list*))
有办法做到这一点吗?如果是这样,怎么样?
如果项目符合某些条件,我想要操纵该项目,如果不匹配则忽略它。因此,List.filter似乎不是解决方案。
答案 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)
Batteries和Extlib都提供了等效的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)