10

How to use LINQ to remove certain elements from a IList based on another IList. I need to remove records from list1 where ID is present in list2. Below is the code sample,

class DTO
{

    Prop int ID,
    Prop string Name
}

IList<DTO> list1;

IList<int> list2;



foreach(var i in list2)
{
    var matchingRecord = list1.Where(x.ID == i).First();
    list1.Remove(matchingRecord);
}

This is how I am doing it, is there a better way to do the same.

3 Answers3

23

You could write a "RemoveAll()" extension method for IList<T> which works exactly like List.RemoveAll(). (This is generally useful enough to keep in a common class library.)

For example (error checking removed for clarity; you'd need to check the parameters aren't null):

public static class IListExt
{
    public static int RemoveAll<T>(this IList<T> list, Predicate<T> match)
    {
        int count = 0;

        for (int i = list.Count - 1; i >= 0; i--)
        {
            if (match(list[i]))
            {
                ++count;
                list.RemoveAt(i);
            }
        }

        return count;
    }        

Then to remove the items from list1 as required would indeed become as simple as:

list1.RemoveAll(item => list2.Contains(item.ID));
Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
16

I would use this approach:

var itemsToRemove = list1.Where(x => list2.Contains(x.ID)).ToList();
foreach(var itemToRemove in itemsToRemove)
    list1.Remove(itemToRemove);

This approach removes the items in place. It is best used for cases where there are many items in list1 and few in list2.
If the amount of items in list1 and list2 is similar, the approach from Cuong Le is a good alternative.

Daniel Hilgarth
  • 171,043
  • 40
  • 335
  • 443
9

You can use Where for simpler:

list1 = list1.Where(x => !list2.Contains(x.ID))
             .ToList();

But you really need to remove in place, prefer @DanielHilgarth's answer

cuongle
  • 74,024
  • 28
  • 151
  • 206