将选项列表映射到字符串列表
Map a list of options to list of strings
我在 OCaml 中有以下功能:
let get_all_parents lst =
List.map (fun (name,opt) -> opt) lst
将 (name, opt)
的大列表映射到 opt
的列表。选项可以包含 None
或 Some value
,在本例中是一个字符串。我想要一个包含我所有值的 strings 列表。
我是OCaml的初学者
我将扩展@Carsten 的回答。他为你指明了正确的方向。
不清楚你问的是什么问题。例如,我不确定您为什么要告诉我们您的函数 get_all_parents
。可能此功能是您尝试获得所需答案的尝试,但它并不适合您。或者,也许您对这个函数很满意,但是您想对其结果做一些进一步的处理?
无论哪种方式,List.map
都无法完成整个工作,因为它总是 returns 一个与其输入长度相同的列表。但是您需要一个长度可以不同的列表,具体取决于大列表中有多少 None
个值。
所以你需要一个函数,它可以只提取列表中你感兴趣的部分。正如@Carsten 所说,关键函数是 List.filter
。
map
和 filter
的某种组合绝对可以满足您的需求。或者您可以只使用 fold
,它兼具 map
和 filter
的强大功能。或者您可以编写自己的递归函数来完成所有工作。
更新
也许您的问题在于从 string option
中提取 string
。 "nice" 方法是在选项为 None
:
时提供一个默认值
let get default xo =
match xo with
| None -> default
| Some x -> x
# get "none" (Some "abc");;
- : string = "abc"
# get "none" None;;
- : string = "none"
#
我不认为 filter
和 map
一起使用是解决这个问题的好方法。这是因为当您应用 map
将您的 string option
转换为 string
时,您将需要处理 None
的情况。即使 you 知道你不会有任何 None
因为你 filter
ed 他们走了,类型检查器没有,也无能为力你。如果您启用了非详尽的模式匹配警告,您将得到它们,或者您将不得不为 None
情况提供某种虚拟字符串。而且,您将不得不希望您在以后重构时不要引入错误,或者编写测试用例或进行更多代码审查。
相反,您需要一个函数 filter_map : ('a -> 'b option) -> 'a list -> 'b list
。这个想法是,这像 map
一样工作,除了 filter_map f lst
删除 lst
的每个元素,f
计算为 None
。如果 f
的计算结果为 Some v
,则结果列表将包含 v
。然后你可以像这样使用 filter_map
:
filter_map (fun (_, opt) -> opt) lst
你也可以写成
filter_map snd lst
一个更一般的例子是:
filter_map (fun (_, opt) ->
match opt with
| Some s -> Some (s ^ "\n")
| None -> None)
lst
filter_map
可以这样实现:
let filter_map f lst =
let rec loop acc = function
| [] -> List.rev acc
| v::lst' ->
match f v with
| None -> loop acc lst'
| Some v' -> loop (v'::acc) lst'
in
loop [] lst
编辑 为了更加完整,您还可以
let filter_map f lst =
List.fold_left (fun acc v ->
match f v with
| Some v' -> v'::acc
| None -> acc) [] lst
|> List.rev
可惜标准库中没有这种函数。它存在于 Batteries Included and Jane Street Core.
中
type opt = Some of string | None
List.fold_left (fun lres -> function
(name,Some value) -> value::lres
| (name,None) -> lres
) [] [("s1",None);("s2",Some "s2bis")]
结果:
- : string list = ["s2bis"]
我在 OCaml 中有以下功能:
let get_all_parents lst =
List.map (fun (name,opt) -> opt) lst
将 (name, opt)
的大列表映射到 opt
的列表。选项可以包含 None
或 Some value
,在本例中是一个字符串。我想要一个包含我所有值的 strings 列表。
我是OCaml的初学者
我将扩展@Carsten 的回答。他为你指明了正确的方向。
不清楚你问的是什么问题。例如,我不确定您为什么要告诉我们您的函数 get_all_parents
。可能此功能是您尝试获得所需答案的尝试,但它并不适合您。或者,也许您对这个函数很满意,但是您想对其结果做一些进一步的处理?
无论哪种方式,List.map
都无法完成整个工作,因为它总是 returns 一个与其输入长度相同的列表。但是您需要一个长度可以不同的列表,具体取决于大列表中有多少 None
个值。
所以你需要一个函数,它可以只提取列表中你感兴趣的部分。正如@Carsten 所说,关键函数是 List.filter
。
map
和 filter
的某种组合绝对可以满足您的需求。或者您可以只使用 fold
,它兼具 map
和 filter
的强大功能。或者您可以编写自己的递归函数来完成所有工作。
更新
也许您的问题在于从 string option
中提取 string
。 "nice" 方法是在选项为 None
:
let get default xo =
match xo with
| None -> default
| Some x -> x
# get "none" (Some "abc");;
- : string = "abc"
# get "none" None;;
- : string = "none"
#
我不认为 filter
和 map
一起使用是解决这个问题的好方法。这是因为当您应用 map
将您的 string option
转换为 string
时,您将需要处理 None
的情况。即使 you 知道你不会有任何 None
因为你 filter
ed 他们走了,类型检查器没有,也无能为力你。如果您启用了非详尽的模式匹配警告,您将得到它们,或者您将不得不为 None
情况提供某种虚拟字符串。而且,您将不得不希望您在以后重构时不要引入错误,或者编写测试用例或进行更多代码审查。
相反,您需要一个函数 filter_map : ('a -> 'b option) -> 'a list -> 'b list
。这个想法是,这像 map
一样工作,除了 filter_map f lst
删除 lst
的每个元素,f
计算为 None
。如果 f
的计算结果为 Some v
,则结果列表将包含 v
。然后你可以像这样使用 filter_map
:
filter_map (fun (_, opt) -> opt) lst
你也可以写成
filter_map snd lst
一个更一般的例子是:
filter_map (fun (_, opt) ->
match opt with
| Some s -> Some (s ^ "\n")
| None -> None)
lst
filter_map
可以这样实现:
let filter_map f lst =
let rec loop acc = function
| [] -> List.rev acc
| v::lst' ->
match f v with
| None -> loop acc lst'
| Some v' -> loop (v'::acc) lst'
in
loop [] lst
编辑 为了更加完整,您还可以
let filter_map f lst =
List.fold_left (fun acc v ->
match f v with
| Some v' -> v'::acc
| None -> acc) [] lst
|> List.rev
可惜标准库中没有这种函数。它存在于 Batteries Included and Jane Street Core.
中type opt = Some of string | None
List.fold_left (fun lres -> function
(name,Some value) -> value::lres
| (name,None) -> lres
) [] [("s1",None);("s2",Some "s2bis")]
结果:
- : string list = ["s2bis"]