必须是更好的方法,我敢肯定......
// Simplified code
var a = new List<int>() { 1, 2, 3, 4, 5, 6 };
var b = new List<int>() { 2, 3, 5, 7, 11 };
var z = new List<int>();
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), i.e. { 2, 3, 5 }
我不介意使用上述技术,但我想要快速有效的东西(我需要比较非常大的列表&lt;&gt;多次),这似乎都不是!有什么想法吗?
编辑:因为它有所不同 - 我使用的是.NET 4.0,初始数组已经排序并且不包含重复数据。
答案 0 :(得分:6)
您可以使用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];
}
}
这是你需要添加一些单元测试的地方;)
修改强> 最后一点 - 很可能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];
}
}
答案 1 :(得分:2)
有IEnumerable.Intersect,但由于这是一种扩展方法,我怀疑它会非常有效。
如果你想要效率,拿一个列表然后把它变成一个Set,然后翻看第二个列表,看看集合中有哪些元素。请注意,我预先分配z
,以确保您不会遭受任何重新分配。
var set = new HashSet<int>(a);
var z = new List<int>(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)
,我相信它会同样有效,但我不是百分百肯定。
答案 2 :(得分:1)
答案 3 :(得分:1)
如果您可以使用LINQ,则可以使用Enumerable.Intersect()
扩展方法。
答案 4 :(得分:1)
在System.Collections.Generic
命名空间中使用SortedSet<T>
:
SortedSet<int> a = new SortedSet<int>() { 1, 2, 3, 4, 5, 6 };
SortedSet<int> b = new SortedSet<int>() { 2, 3, 5, 7, 11 };
b.IntersectWith(s2);
但你肯定没有重复!
虽然您的第二个列表不需要是SortedSet
。它可以是任何集合(IEnumerable<T>
),但在内部,该方法的作用方式是,如果第二个列表也是SortedSet<T>
,则该操作是O(n)操作。