ocaml - 找到没有重复的对列表的并集
问题描述
如果两个键匹配,则将具有最高值的对添加到列表中。例如,[("a",1);("a",4);("b",2)]
U [("a",5);("b",1);("c",3)]
= [("a",5);("b",2);("c",3)]
。
我尝试创建一个函数,将给定对与另一个列表对进行比较:
`let max_val (k,v) o_lst = if (v > (List.assoc k o_lst)) then (k,v) else (k,(List.assoc k o_lst))`
这将返回具有最大值的对,您可以假设列表在调用此函数之前按降序排序。但是,这个函数的一个明显错误是,如果具有相同键的多个对具有比另一个列表更大的值,那么它们也会被添加到新列表中。
我不确定如何正确执行此操作。学习 Ocaml
解决方案
一种方法是将列表转换为地图,并使用Map
模块的merge
功能加入它们:
module StrMap = Map.Make(String)
let list1 = [ "a", 1; "a", 4; "b", 2 ]
let list2 = [ "a", 5; "b", 1; "c", 3 ]
let map1 = List.to_seq list1 |> StrMap.of_seq
let map2 = List.to_seq list2 |> StrMap.of_seq
let max_merge =
StrMap.merge (fun key x y ->
match x, y with
| Some a, None -> Some a
| None, Some b -> Some b
| Some a, Some b -> Some (max a b)
| None, None -> None (* Shouldn't happen but silences a warning. *))
let map3 = max_merge map1 map2
let list3 = StrMap.bindings map3 (* [("a", 5); ("b", 2); ("c", 3)] *)
创建映射时,如果您在添加的对列表中有重复的键,则最后一个将用于最终映射 - 因此,如果您的列表已经排序,您将获得最高的键。然后将这两个映射合并在一起,当两者都存在一个键时,使用最大值。
或者,如果您可以使用 Jane Street 的Base替换标准库,它的List
模块中有许多相关的有用功能:
open Base
let list1 = [ "a", 1; "a", 4; "b", 2 ]
let list2 = [ "a", 5; "b", 1; "c", 3 ]
let apply_first (a,_) (b,_) ~f = f a b
let max_merge a b =
List.merge a b ~compare:(fun (xs, xi) (ys, yi) ->
let cmp = String.compare xs ys in
if cmp = 0 then Int.compare xi yi else cmp) |>
List.remove_consecutive_duplicates ~which_to_keep:`Last
~equal:(apply_first ~f:String.equal)
let list3 = max_merge list1 list2 (* [("a", 5); ("b", 2); ("c", 3)] *)
使用Core
or可以让你通过模块的功能Core_kernel
稍微简化它:Tuple
compare
open Core
let list1 = [ "a", 1; "a", 4; "b", 2 ]
let list2 = [ "a", 5; "b", 1; "c", 3 ]
let apply_first (a,_) (b,_) ~f = f a b
let max_merge a b =
List.merge a b ~compare:(Tuple.T2.compare ~cmp1:String.compare ~cmp2:Int.compare) |>
List.remove_consecutive_duplicates ~which_to_keep:`Last
~equal:(apply_first ~f:String.equal)
let list3 = max_merge list1 list2
最后,为了更好地衡量,第一个使用 Base/Core 的算法Map
,它的接口与 Stdlib 的接口非常不同:
open Base
let list1 = [ "a", 1; "a", 4; "b", 2 ]
let list2 = [ "a", 5; "b", 1; "c", 3 ]
let list_to_map = Map.of_alist_reduce (module String) ~f:max
let map1 = list_to_map list1
let map2 = list_to_map list2
let max_merge = Map.merge_skewed ~combine:(fun ~key a b -> max a b)
let map3 = max_merge map1 map2
let list3 = Map.to_alist map3
推荐阅读
- java - 无法使用 Retrofit2 获取数据
- java - 如何用用户数据填充导航抽屉
- php - 如何仅显示 .mp4 文件?
- yaml - yaml中的破折号和缩进
- c - 将 16 位写入文件(并确保它正在发生)
- html - HTMLKit Swift 解析
- java - 带有 ParameterizedTypeReference 的 Spring WebClient 不起作用
- duplicates - 在电源查询中查找重复行并将第一行标记为 1 并将剩余的重复行标记为 0
- javascript - 如何防止自定义表单重定向到谷歌表单提交响应页面?
- c# - 必须在配置中注册 WebResource.axd 处理程序才能处理此请求。(RDLC 报告运行时)