9

Sorry to post such basic questions, I'm new to LINQ and am trying to figure out the best way to do this short of looping through each IList.

I have 2 ILists<> with of custom dto objects. I want to remove all the matching items from on list that are in the other.

IList<ItemDTO> list1 = itemsbl.GetBestItems();
IList<ItemDTO> list2 = itemsbl.GetWorstItems();

I need to remove all the items in list1 from list2. I have been looking at the Except() method but apparently i need my ItemsDTO class to override the GetHashCode and Equals methods for that to work, but i am having trouble finding some examples of this.

Could someone please show me the best way to remove list1 from list2?

Thanks again

Orkun
  • 6,998
  • 8
  • 56
  • 103
Nugs
  • 5,503
  • 7
  • 36
  • 57

4 Answers4

9

You can probably use the Except method to do this.

var newList = list2.Except(list1).ToList();

If you want to replace list2 then just do this:

list2 = list2.Except(list1).ToList();

From MSDN:

To compare custom data types, implement the IEquatable generic interface and provide your own GetHashCode and Equals methods for the type. The default equality comparer, Default, is used to compare values of types that implement IEquatable.

Dismissile
  • 32,564
  • 38
  • 174
  • 263
  • Thank you, i ended up modifying my class accordingly so that i can us Except()... Thank you everyone, i'm sure all the other solutions were just as good... :) – Nugs Feb 16 '12 at 19:49
1

Hash it definitely a good way, @Jon Skeet below answer to a similar question will provide you with the solution.

so basically the syntax is:

 var setToRemove = new HashSet<ItemDTO>(list1);
 list2.RemoveAll(x => setToRemove.Contains(x));

Using LINQ to remove elements from a List<T>

hopefully this helps.

Community
  • 1
  • 1
Nickz
  • 1,880
  • 17
  • 35
  • I do not know why, but RemoveAll() is not an option for me... – Nugs Feb 15 '12 at 23:32
  • 3
    IList is the interface which List implements.IList is used for other collection classes. The List class contains methods which may not be defined in IList. So by assigning your orginal list object to IList you will no longer have access to any unique methods of List. Unless you have a reason for using IList, I'd recommend using List. MSDN: http://msdn.microsoft.com/en-us/library/6sh2ey19.aspx – Nickz Feb 15 '12 at 23:36
1
var list1 = new List<string> { "A", "B", "C" };
var list2 = new List<string> { "A", "C", "E", "B", "D", "G", "F" };
list2.RemoveAll(list1.Contains);

will work, too. Note that the list1.Contains is actually a lambda

s => list1.Contains(s)

-A.

Ani
  • 10,826
  • 3
  • 27
  • 46
  • I do not know why, but RemoveAll() is not an option for me... – Nugs Feb 15 '12 at 23:25
  • `list.Contains` is not actually a lambda. Althought it behaves the same here. – svick Feb 16 '12 at 01:01
  • 1
    I mentioned that because I thought it important that RemoveAll takes a predicate, especially since the OP's objects might not have equality/comparison implemented. – Ani Feb 16 '12 at 04:56
  • RemoveAll only exists on List. If you're using IList then you're stuck without it. – Carl Bussema Dec 14 '12 at 21:30
  • As already stated, IList doesn't contain the `RemoveAll` method – Luke Dec 28 '15 at 13:22
  • @Coulton The clarifications were an edit. The initial question was unclear and I left the answer here for others to find. Thanks for the downvote anyways. – Ani Dec 28 '15 at 19:17
0

What it means is that you need to tell the .net runtime how to determine whether two instances of a class are equal (e.g. how should it define whether one instance of ItemDTO is equal to another instance of ItemDTO).

to do this, override Equals

public class ItemDTO
{
    public override bool Equals(object obj)
    {
        var otherItem = obj as ItemDTO;

        if (otherItem == null)
        {
            // this will be because either 'obj' is null or it is not of type ItemDTO.
            return false;
        }

        return otherItem.SomeProperty == this.SomeProperty 
               && otherItem.OtherProperty == this.OtherProperty;
    }
}

If you don't do this, it will only remove any references in the list which point to the same physical instance as the other. You can then use the Except or RemoveAll methods or what ever other method you decide to use.

You will also need to override GetHashcode, see the link below for further info on that.

See Guidelines for Overloading Equals and GetHashcode

Trevor Pilley
  • 16,156
  • 5
  • 44
  • 60