现在有三个选项 - 前两个更通用,因为它们不依赖于MillionIntegerList
排序(最初没有指定)。在大列表已经排序的情况下,第三个更可取。
选项1
是的,使用 LINQ 肯定有更好的方法:
var common = MillionIntegerList.Intersect(TwoThousandIntegerList).ToList();
这将在内部使用通过HashSet<int>
构建的TwoThousandIntegerList
,然后查找其中的每个元素——这将比每次MillionIntegerList
都遍历整个元素要高效得多。TwoThousandIntegerList
如果您只想要非黑名单,您需要:
var valid = MillionIntegerList.Except(TwoThousandIntegerList).ToList();
请注意,如果您只需要对结果进行一次迭代,则应删除该ToList
调用 - 我已将其包含在内以实现结果,以便可以廉价地多次检查它们。如果您只是在迭代,则Intersect
or的返回值Except
只会流式传输结果,从而在内存使用方面便宜得多。
选项 2
如果您不想依赖 LINQ to Objects 的实现细节,但仍需要基于哈希的方法:
var hashSet = new HashSet<int>(TwoThousandIntegerList);
hashSet.IntersectWith(MillionIntegerList);
// Now use hashSet
选项 3
使用大列表已排序这一事实的方法肯定会很有用。
假设您也不介意先对黑名单进行排序,您可以编写一个像这样的流(和通用)实现(未经测试):
// Note: to use this, you'd need to make sure that *both* sequences are sorted.
// You could either sort TwoThousandIntegerList in place, or use LINQ's OrderBy
// method.
public IEnumerable<T> SortedIntersect<T>(this IEnumerable<T> first,
IEnumerable<T> second) where T : IComparable<T>
{
using (var firstIterator = first.GetEnumerator())
{
if (!firstIterator.MoveNext())
{
yield break;
}
using (var secondIterator = second.GetEnumerator())
{
if (!secondIterator.MoveNext())
{
yield break;
}
T firstValue = firstIterator.Current;
T secondValue = secondIterator.Current;
while (true)
{
int comparison = firstValue.CompareTo(secondValue);
if (comparison == 0) // firstValue == secondValue
{
yield return firstValue;
}
else if (comparison < 0) // firstValue < secondValue
{
if (!firstIterator.MoveNext())
{
yield break;
}
firstValue = firstIterator.Current;
}
else // firstValue > secondValue
{
if (!secondIterator.MoveNext())
{
yield break;
}
secondValue = secondIterator.Current;
}
}
}
}
}
(如果你愿意,你可以采用 aIComparer<T>
而不是依赖于 T 具有可比性。)