F# Seq diff

14

给定两个序列,如何获取属于两个序列或者其中一个序列独有的所有元素?

例子:

let a = [1..10]
let b = [3; 5; 7]

如何计算列表中共同元素3、5和7,以及1、2、4、6、8、9和10之外的所有元素。

谢谢。


你能举个例子吗? - Dario
3个回答

14

你想要做的不过是简单的集合操作,包括交集差集(或补集)。

F# 有 Set 模块来帮助我们处理这个问题。下面的代码应该能解决问题:

let a = [1 .. 10]
let b = [3; 5; 7]

let intersection = Set.intersect (Set.ofList a) (Set.ofList b)
let difference = (Set.ofList a) - (Set.ofList b)

如果你愿意的话,你当然可以使用 Set.toList 将结果转换回列表形式。

正如Mehrdad指出的那样,这也可以通过使用 LINQ(或甚至是BCL中的 HashSet 类)进行替代,但这种方法似乎最符合F#语言的精神(肯定在语法上最好,可能也是最有效率的)。


1
需要考虑的一个问题是,将列表转换为集合时,只保留不同的值(即集合的定义)。Mehrdad 给出的答案(使用 Linq-Enumerable 方法)将保留所有值,甚至包括不同的值。有时这不是一个问题,但我只是想指出这一点。 - polkduran
1
(Set.of_list a)-(Set.of_list b)不是可交换的。 - Indy9000

9
略微紧凑一些:
let a = set [0;1;2;3]
let b = set [2;3;4;5]
let c = a - b
let d = b - a
let e = Set.intersect a b
let f = a + b
> 
val c : Set<int> = seq [0; 1]
val d : Set<int> = seq [4; 5]
val e : Set<int> = seq [2; 3]
val f : Set<int> = seq [0; 1; 2; 3; ...]

丹尼


5

我知道的方法不太符合F#的风格。你可以使用.NET库。 seq<T> 只是一个普通的 IEnumerable<T>,没有什么特别之处:

let diff = System.Linq.Enumerable.Except(seq1, seq2); // seq1 - seq2
let intersect = System.Linq.Enumerable.Intersect(seq1, seq2);
let symdiff = System.Linq.Enumerable.Union(System.Linq.Enumerable.Except(seq1, seq2), System.Linq.Enumerable.Except(seq2, seq1));

1
它们可以工作,但我认为对于一个如此重度依赖序列的语言来说,没有自己的方法(或别名)来处理这样一个常见任务是很奇怪的... - pistacchio
1
同意。可能有更F#的方式。只是提出了可能性。等待更好的答案。 - Mehrdad Afshari

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接