How do I do an integer list intersection while keeping duplicates?
ILookup<int, int> lookup1 = list1.ToLookup(i => i);
ILookup<int, int> lookup2 = list2.ToLookup(i => i);
int[] result =
(
from group1 in lookup1
let group2 = lookup2[group1.Key]
where group2.Any()
let smallerGroup = group1.Count() < group2.Count() ? group1 : group2
from i in smallerGroup
select i
).ToArray();
The where expression is technically optional, I feel it makes the intent clearer.
If you want more terse code:
ILookup<int, int> lookup2 = list2.ToLookup(i => i);
int[] result =
(
from group1 in list1.GroupBy(i => i)
let group2 = lookup2[group1.Key]
from i in (group1.Count() < group2.Count() ? group1 : group2)
select i
).ToArray();
I wrote this extension to solve the problem:
public static IEnumerable<T> Supersect<T>(this IEnumerable<T> a, ICollection<T> b)
=> a.Where(b.Remove);
example:
var a = new List<int> { 1, 2, 2, 2, 3, 3, 4, 5 };
var b = new List<int> { 1, 1, 2, 2, 3, 3, 3, 4, 4};
var result = a.Supersect(b);
result:
{ 1, 2, 2, 3, 3, 4 }