Ocaml 查找没有重复项的对列表的并集

Ocaml 查找没有重复项的对列表的并集,ocaml,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))` 这将返回具有最大值的对

如果两个键匹配,则具有最高值的一对将添加到列表中。 例如,
[(“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

您的函数使用单对。这可能有助于从一个更高的层次来思考,从一系列成对的角度来考虑

获得所需结果的一种方法(在我看来)是附加两个列表,然后按键(作为主排序键)对结果列表进行排序,然后按降序值(作为辅助排序键)对结果列表进行排序。之后,您可以应用一个“uniq”函数来抑制除第一次出现的每个键以外的所有键


你说你无论如何都计划对列表进行排序。所以唯一的新功能是“uniq”函数。事实上,如果您正确定义比较,您可能可以使用
List.sort\u uniq
。如果这不起作用,您可以编写自己的“uniq”函数(在移动窗口中一次查看列表的两个元素)。

一种方法是将列表转换为地图,并使用
Map
模块的
merge
函数将它们连接起来:

模块StrMap=Map.Make(字符串)
让列表1=[“a”,1;“a”,4;“b”,2]
让列表2=[“a”,5;“b”,1;“c”,3]
设map1=List.to|seq list1 |>StrMap.of|seq
设map2=List.to_seq list2 |>StrMap.of_seq
让max_合并=
StrMap.merge(趣味键x y->
将x,y与
|有些a,没有->有些a
|无,一些b->一些b
|一些a,一些b->一些(最大a b)
|无,无->无(*不应出现,但会使警告静音。*))
设map3=max\u合并map1 map2
让list3=StrMap.bindings映射3(*[((“a”,5);(“b”,2);(“c”,3)]*)
创建映射时,如果要添加的对列表中有重复的键,则最后一个键将用于最终映射-因此,如果列表已排序,则会得到最高的键。然后将这两个映射合并在一起,当其中都存在一个键时,将使用最大值


或者,如果您可以使用Jane Street的替换标准库,它的
列表
模块中有许多相关的有用功能:

openbase
让列表1=[“a”,1;“a”,4;“b”,2]
让列表2=[“a”,5;“b”,1;“c”,3]
让我们先应用_(a,)(b,)~f=fab
让max_合并a b=
List.merge a b~比较:(fun(xs,xi)(ys,yi)->
让cmp=String.compare中的xs-ys
如果CMP=0,则比较“席益”CMP>>
List.remove_连续的_重复项~要保留的:`Last
~equal:(首先应用~f:String.equal)
让list3=max_merge list1 list2(*[((“a”,5);(“b”,2);(“c”,3)]*)
使用
Core
Core\u kernel
可以使用
Tuple
模块的
compare
函数将其简化一点:

opencore
让列表1=[“a”,1;“a”,4;“b”,2]
让列表2=[“a”,5;“b”,1;“c”,3]
让我们先应用_(a,)(b,)~f=fab
让max_合并a b=
List.merge a b~比较:(Tuple.T2.compare~cmp1:String.compare~cmp2:Int.compare)|>
List.remove_连续的_重复项~要保留的:`Last
~equal:(首先应用~f:String.equal)
让list3=max\u合并list1 list2
最后,为了更好地衡量,第一个算法使用了Base/Core
Map
,它与Stdlib有一个非常不同的接口:

openbase
让列表1=[“a”,1;“a”,4;“b”,2]
让列表2=[“a”,5;“b”,1;“c”,3]
让list_to_map=map.of_alist_reduce(模块字符串)~f:max
让map1=列表到映射列表1
让map2=列表到映射列表2
让max_merge=Map.merge_skewed~combine:(乐趣~key a b->max a b)
设map3=max\u合并map1 map2
让list3=Map.to_-alist map3
您可以使用
Map.Make(String)
作为累加器

让我们选择_max=
让模块StrMap=Map.Make(字符串)进入
让rec处理acc=功能
|((k,v)::t::src->
让acc=将StrMap.find_opt k acc与匹配
|当vmax>=v->acc时的一些vmax
|一些|无->acc |>StrMap.remove k
|>StrMap.addk v in
过程acc(t::src)
|[]::src->process acc src
|[]->StrMap.bindings acc in
进程StrMap.empty
让测试=选择_max
[“a”,7;“a”,9;“a”,1];
[“a”,1;“b”,5;“c”,7];
[“c”,5;“c”,5;“b”,7]
]
val select_max:(String.t*int)list->(String.t*int)list=

val测试:(String.t*int)list=[(“a”,9);(“b”,7);(“c”,7)]