我有两个集合(它们恰好是数组,但我认为它并不重要):L
和R
。它们都已排序,现在我想比较它们。我想最终得到两个集合:每个输入数组一个包含不在另一个中的项目。
我可以从L
获取第一项,然后搜索R
,如果没有匹配,则将其添加到我的“唯一”集合(Lu
)。但这种效率非常低,而且我希望在不久的将来能够处理一些非常大的集合。
我虽然可能“玩跳房子”:
第1步:选择两个列表L
和R
,并比较每个列表的头部(l :: L
和r :: R
):
分支1:如果l
< r
,然后将l
添加到Lu
并递归,传入L
和r :: R
分支2:如果l
> r
,然后将r
添加到Ru
并递归,传入l :: L
和R
分支3:如果l
= r
,则递归,传入L
和R
第2步:返回Lu
和Ru
我可以编写这个函数,但在我努力之前,我想知道是否已经存在一个可以为我做这个的函数。这似乎是一个不常见的场景,而且我总是宁愿使用现有的解决方案来推动自己的解决方案。
(另外,如果这个算法有一个更易识别的名称,我想知道它叫什么。)
答案 0 :(得分:8)
(我在2小时前写过上面的问题。从那以后,我自己找到了答案。以下是我发现的。)
在集合论中,L中但不在R中的项目的“列表”被称为“L中的R的相对补集”,也称为“L和R的集合理论差异”
(参见维基百科的Complement (set theory)文章)
作为一种数学语言的F#将这个概念融入到它的核心库中。首先,您需要将集合构建为集合:
// example arrays:
let arr1 = [| 1; 2; 3 |]
let arr2 = [| 2; 3; 4 |]
// build the L and R sets
let L = set arr1
let R = set arr2
现在你可以调用“差异”函数并快速获得每个数组的相对补码:
let Lu = Set.difference L R |> Set.toArray
let Ru = Set.difference R L |> Set.toArray
> val Lu : int [] = [|1|]
> val Ru : int [] = [|4|]
语法也更短。 Set类型有overloaded the minus operator。 Set.difference
只是从第一个参数中减去第二个参数,因此您实际上可以使用以下参数:
let Lu = L - R |> Set.toArray
let Ru = R - L |> Set.toArray
> val Lu : int [] = [|1|]
> val Ru : int [] = [|4|]