2

If I have two generic lists. How do I find what's NOT in the other list using LINQ?

Here is my obj class:

 public class tobj
 {      
    public string column1;
    public string column2;
 }  

Here are the arrays

 tobj[] array1 = 
 { 
        new tobj { "1", "1" }, new tobj { "2", "2" }, new tobj { "3", "3" } 
 };

 tobj[] array2 = 
 { 
     new tobj { "2", "2" }, new tobj { "3", "3" }, new tobj { "4", "4" } 
 };

 var diff = array1.FinfDiff(array2); 

 foreach (var value in diff)
 {
    Console.WriteLine(value.column1); // 1
 }

This code not tested yet.

Phil
  • 42,255
  • 9
  • 100
  • 100
Luke101
  • 63,072
  • 85
  • 231
  • 359

3 Answers3

4

You can use Except. Given that you have a custom type, though, you'll want to override Equals() and GetHashCode() so that it works well with Linq.

This is because Linq strives for efficiency, so it can use HashSet<T> and other mechanisms to quickly determine if items are possibly equivalent or not (items that are equivalent must have same hash code, or your hash code is bad). So it's not just enough to implement Equals(), you must also implement GetHashCode() when using methods of this type with custom classes.

For example:

    public class tobj : IEquatable<tobj>
    {
        public string column1;
        public string column2;

        public bool Equals(tobj other)
        {
            return other != null ? Equals(column1, other.column1) && Equals(column2, other.column2) : false;
        }

        public override bool Equals(object obj)
        {
            return Equals(obj as tobj);
        }

        public override int GetHashCode()
        {
            // seed the code
            int hash = 13;

            // use some primes to mix in the field hash codes...
            hash = hash * 17 + column1.GetHashCode();
            hash = hash * 17 + column2.GetHashCode();

            return hash
        }
    }  

Now that you have GetHashCode() and Equals() overridden (I like implementing IEquatable<T> myself as well), you can use Except():

        var results = array1.Except(array2);

        foreach (var i in results)
        {
            Console.WriteLine(i.column1 + ":" + i.column2);
        }

I'd recommend seeing this SO thread on algorithms for hash codes as well for tips on implementing a good one.

Also, as a side note, some types (such as KeyValuePair, Tuple, and anonymous types) already implement Equals() and GetHashCode() correctly for equivalence in such a way that they take into account their individual components.

Community
  • 1
  • 1
James Michael Hare
  • 37,767
  • 9
  • 73
  • 83
2

You can use the Except method available to IEnumerable. It's easy to implement. You can see an example outlined here: http://msdn.microsoft.com/en-us/library/bb336390.aspx

Josh
  • 2,955
  • 1
  • 19
  • 28
0
array2.ForEach(x => array1.Remove(x));

what stays in array1 is your result

edit: I dont look at first sight, that items are not "simple" objects... as James write, you need to override equal

sasjaq
  • 761
  • 1
  • 11
  • 31