使用LINQ,这很简单,因为您可以在Enumerable class 上调用Intersect extension method 来为您提供两个数组的集合交集:
var intersection = ListA.Intersect(ListB);
但是,这是 set 交集,这意味着如果 ListA 和 ListB 没有唯一值,您将不会获得任何副本。换句话说,如果您有以下情况:
var ListA = new [] { 0, 0, 1, 2, 3 };
var ListB = new [] { 0, 0, 0, 2 };
然后ListA.Intersect(ListB) 产生:
{ 0, 2 }
如果你期待:
{ 0, 0, 2 }
然后,您将不得不自己维护项目的计数,并在扫描两个列表时进行产量/递减。
首先,您需要收集带有单个项目列表的Dictionary<TKey, int>:
var countsOfA = ListA.GroupBy(i => i).ToDictionary(g => g.Key, g => g.Count());
从那里,您可以扫描 ListB 并在遇到 countsOfA 中的项目时将其放入列表中:
// The items that match.
IList<int> matched = new List<int>();
// Scan
foreach (int b in ListB)
{
// The count.
int count;
// If the item is found in a.
if (countsOfA.TryGetValue(b, out count))
{
// This is positive.
Debug.Assert(count > 0);
// Add the item to the list.
matched.Add(b);
// Decrement the count. If
// 0, remove.
if (--count == 0) countsOfA.Remove(b);
}
}
您可以将其包装在一个延迟执行的扩展方法中,如下所示:
public static IEnumerable<T> MultisetIntersect(this IEnumerable<T> first,
IEnumerable<T> second)
{
// Call the overload with the default comparer.
return first.MultisetIntersect(second, EqualityComparer<T>.Default);
}
public static IEnumerable<T> MultisetIntersect(this IEnumerable<T> first,
IEnumerable<T> second, IEqualityComparer<T> comparer)
{
// Validate parameters. Do this separately so check
// is performed immediately, and not when execution
// takes place.
if (first == null) throw new ArgumentNullException("first");
if (second == null) throw new ArgumentNullException("second");
if (comparer == null) throw new ArgumentNullException("comparer");
// Defer execution on the internal
// instance.
return first.MultisetIntersectImplementation(second, comparer);
}
private static IEnumerable<T> MultisetIntersectImplementation(
this IEnumerable<T> first, IEnumerable<T> second,
IEqualityComparer<T> comparer)
{
// Validate parameters.
Debug.Assert(first != null);
Debug.Assert(second != null);
Debug.Assert(comparer != null);
// Get the dictionary of the first.
IDictionary<T, long> counts = first.GroupBy(t => t, comparer).
ToDictionary(g => g.Key, g.LongCount(), comparer);
// Scan
foreach (T t in second)
{
// The count.
long count;
// If the item is found in a.
if (counts.TryGetValue(t, out count))
{
// This is positive.
Debug.Assert(count > 0);
// Yield the item.
yield return t;
// Decrement the count. If
// 0, remove.
if (--count == 0) counts.Remove(t);
}
}
}
请注意,这两种方法都是O(N + M)(如果我在这里使用 Big-O 表示法,我深表歉意)其中N 是第一个数组中的项目数,M 是第二个数组中的项目。您只需扫描每个列表一次,并且假定获取哈希码并在哈希码上执行查找是一个O(1)(常量)操作。