Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I do an integer list intersection while keeping duplicates?

I'm working on a Greatest Common Factor and Least Common Multiple assignment and I have to list the common factors. Intersection() won't work because that removes duplicates. Contains() won't work because if it sees the int in the second list it returns all matching ints from the first list. Is there a way to do an Intersection that is not Distinct?

edit: sorry for not providing an example, here is what I meant:

if I have the sets:

{1, 2, 2, 2, 3, 3, 4, 5}
{1, 1, 2, 2, 3, 3, 3, 4, 4}

I would want the output

{1, 2, 2, 3, 3, 4}
like image 234
DuckReconMajor Avatar asked Feb 16 '11 02:02

DuckReconMajor


People also ask

Does set intersection remove duplicates?

INTERSECT (alternatively, INTERSECT DISTINCT ) takes only distinct rows while INTERSECT ALL does not remove duplicates from the result rows.

How do you avoid duplicates in lists?

If you don't want duplicates, use a Set instead of a List . To convert a List to a Set you can use the following code: // list is some List of Strings Set<String> s = new HashSet<String>(list); If really necessary you can use the same construction to convert a Set back into a List .

How do you merge two lists without duplicates in Python?

Use set() and list() to combine two lists while removing duplicates in the new list and keeping duplicates in original list. Call set(list_1) and set(list_2) to generate sets of the elements in list_1 and list_2 respectively which contain no duplicates.


2 Answers

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 }
like image 116
Joep Geevers Avatar answered Oct 25 '22 05:10

Joep Geevers


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();
like image 39
Amy B Avatar answered Oct 25 '22 05:10

Amy B