现在有三个选项-前两个比较通用,不依赖于 MillionIntegerList
已经排序(最初没有指定)。第三种情况适用于大型列表已经排序的情况。
选项1
是的,有一个更好的方法,可以使用LINQ:
var common = MillionIntegerList.Intersect(TwoThousandIntegerList).ToList()
这将使用通过TwoThousandIntegerList
构建的HashSet<int>
,然后在其中查找MillionIntegerList
的每个元素 - 这比每次遍历整个TwoThousandIntegerList
要高效得多。
如果您只想要非黑名单中的元素,则需要:
var valid = MillionIntegerList.Except(TwoThousandIntegerList).ToList()
请注意,如果您只需对结果进行一次迭代,则应删除
ToList
调用 - 我已将其包含在内以实现结果的材料化,以便可以以低廉的成本多次检查。如果您只是迭代,
Intersect
或
Except
的返回值将只会
stream结果,这将在内存使用方面更加便宜。
选项2
如果您不想依赖于LINQ to Objects的实现细节,但仍想采用基于哈希的方法:
var hashSet = new HashSet<int>(TwoThousandIntegerList)
hashSet.IntersectWith(MillionIntegerList)
// Now use hashSet
选项3
利用大列表已排序的方法肯定是有用的。
假设您不介意先将黑名单列表排序,那么您可以编写一个流式(并且通用)实现,例如(未经测试):
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)
{
yield return firstValue;
}
else if (comparison < 0)
{
if (!firstIterator.MoveNext())
{
yield break;
}
firstValue = firstIterator.Current;
}
else
{
if (!secondIterator.MoveNext())
{
yield break;
}
secondValue = secondIterator.Current;
}
}
}
}
}
(如果您希望,可以使用
IComparer<T>
来代替依赖于 T 可比较。)