C#两个数组的相似之处

必须有更好的方法来做到这一点,我敢肯定……

// Simplified code var a = new List() { 1, 2, 3, 4, 5, 6 }; var b = new List() { 2, 3, 5, 7, 11 }; var z = new List(); for (int i = 0; i < a.Count; i++) if (b.Contains(a[i])) z.Add(a[i]); // (z) contains all of the numbers that are in BOTH (a) and (b), ie { 2, 3, 5 } 

我不介意使用上述技术,但我想要一些快速有效的东西(我需要多次比较非常大的列表),这似乎都不是! 有什么想法吗?

编辑:因为它有所不同 – 我使用的是.NET 4.0,初始数组已经排序并且不包含重复项。

您可以使用IEnumerable.Intersect。

 var z = a.Intersect(b); 

可能比您当前的解决方案更有效。

请注意,您遗漏了一条重要的信息 – 列表是否正在订购。 如果它们是几个嵌套的循环,它们恰好通过每个输入数组一次,每个都可能更快 – 写起来更有趣。

编辑回复您对订购的评论:

首先尝试循环 – 它需要代表您进行一些调整,但适用于您的初始数据。

  int j = 0; foreach (var i in a) { int x = b[j]; while (x < i) { if (x == i) { z.Add(b[j]); } j++; x = b[j]; } } 

这是你需要添加一些unit testing的地方;)

编辑最后一点 - 很可能Linq可以使用SortedList非常有效地执行此交集,如果性能是一个问题,则值得测试各种解决方案。 如果以无序方式加载数据,请不要忘记将排序考虑在内。

一个最终编辑,因为有一些来回此和人们可能正在使用上面没有正确调试它我在这里发布更高版本:

  int j = 0; int b1 = b[j]; foreach (var a1 in a) { while (b1 <= a1) { if (b1 == a1) z1.Add(b[j]); j++; if (j >= b.Count) break; b1 = b[j]; } } 

有IEnumerable.Intersect,但由于这是一个扩展方法,我怀疑它会非常有效。

如果你想要效率,拿一个列表并把它变成一个Set,然后翻看第二个列表,看看集合中有哪些元素。 请注意,我预先分配z ,只是为了确保您不会遭受任何重新分配。

 var set = new HashSet(a); var z = new List(Math.Min(set.Count, b.Count)); foreach(int i in b) { if(set.Contains(i)) a.Add(i); } 

这保证以O(N + M)运行(N和M是两个列表的大小)。

现在,你可以使用set.IntersectWith(b) ,我相信它会同样有效,但我不是百分百肯定。

Intersect()方法就是这样做的。 来自MSDN :

通过使用默认的相等比较器来比较值,生成两个序列的集合交集。

所以在你的情况下:

 var z = a.Intersect(b); 

System.Collections.Generic命名空间中使用SortedSet

 SortedSet a = new SortedSet() { 1, 2, 3, 4, 5, 6 }; SortedSet b = new SortedSet() { 2, 3, 5, 7, 11 }; b.IntersectWith(s2); 

但是你肯定没有重复!
虽然您的第二个列表不需要是SortedSet 。 它可以是任何集合( IEnumerable ),但在内部,该方法的作用方式是,如果第二个列表也是SortedSet ,则该操作是O(n)操作。

如果可以使用LINQ,则可以使用Enumerable.Intersect()扩展方法。