Compare two List<int>

I would use the Intersect and Except methods:

dups = groupA.Intersect(groupB).ToList();
distinct = groupA.Except(groupB).ToList();

When you remove an item from a list, you move the index of the remaining element down. In essence, you are skipping some items using a for loop.
Try using a while loop, and manually increment the counter when you are not deleting an item.

For example, the following code is incorrect

List<int> nums = new List<int>{2, 4, 6, 7, 8, 10, 11};

for (int i = 0; i < nums.Count; i++)
{
  if (nums[i] % 2 == 0)
    nums.Remove(nums[i]);
}

If will return the list {4, 7, 10, 11} instead of just {7, 11}.

It will not remove the value of 4, because, when I remove the value of 2, (for i=0) the nums list goes from

//index 0  1  2  3  4   5   6 
nums = {2, 4, 6, 7, 8, 10, 11}

to

//index 0  1  2  3  4   5
nums = {4, 6, 7, 8, 10, 11}

The loop finishes, the i is incremented to 1, and the next item referenced is nums[1], which is not 4 as one would intuitively expect, but 6. So in effect the value of 4 is skipped, and the check is not executed.

You should be very, very careful each time when you are modifying the collection you are iterating. For example, the foreach statement will throw an exception if you even try this. In this case you could use a while like

List<int> nums = new List<int>{2, 4, 6, 7, 8, 10, 11};

int i = 0;
while (i < nums.Count)
{
  if (nums[i] % 2 == 0)
  {
    nums.Remove(nums[i])
  }      
  else
  {
    i++; //only increment if you are not removing an item
         //otherwise re-run the loop for the same value of i
  }  
}

of you could even fork the for, like

for (int i = 0; i < nums.Count; i++)
{
  if (nums[i] % 2 == 0)
  {
    nums.Remove(nums[i]);
    i--; //decrement the counter, so that it will stay in place
         //when it is incremented at the end of the loop
  }
}

Alternatively you could use linq, like this:

distinct.AddRange(groupA);
distinct.AddRange(groupB);
distinct = distinct.Distinct().ToList();

and

dups.AddRange(groupA);
dups.AddRange(groupB);

dups = dups.GroupBy(i => i)
           .Where(g => g.Count() > 1)
           .Select(g => g.Key)
           .ToList();

Note that the LINQ code will not alter your existing groupA and groupB lists. If you just want to distinct them, you could just do

groupA = groupA.Distinct().ToList();
groupB = groupB.Distinct().ToList();

You can easily do it with Linq:

    List<int> dups = groupA.Intersect(groupB).ToList();
    List<int> distinct = groupA.Except(groupB).ToList();

(assuming I correctly understood what you were trying to do)

Tags:

C#