Distinct not working in Linq-to-Objects

   I was developing a project that I have and came to the point where I needed to find only the distinct elements of a specific IEnumerable, and that’s when I looked a bit closely to the Distinct Extension Method for IEnumerable, so ok, let me use it, this is just what I need so this should be fairly simple (This was my first mistake. Thinking something should be simple. Shame on me. Smile ).

  Ok, so the Distinct Extension Method has only two overloads that are:

- One that takes no parameters:

public static IEnumerable<TSource> Distinct<TSource>(this IEnumerable<TSource> source);.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }

- A second one that has 1 parameter:

public static IEnumerable<TSource> Distinct<TSource>(this IEnumerable<TSource> source,
 IEqualityComparer<TSource> comparer);


   - What? IEqualityComparer? Why not a Func<TSource, bool> like the others in the family?


  No problem, I just need to implement a IEqualityComparer, that shouldn’t be hard. 


  So I did the following:


    public class SampleComparer : IEqualityComparer<MyObject>
    {
        #region IEqualityComparer<MyObject> Members

        public bool Equals(MyObject x,MyObject y)
        {
            return x.Id.Equals(y.Id);
        }

        public int GetHashCode(MyObject obj)
        {
            return obj.GetHashCode();
        }

        #endregion
    }


  It sounds like almost too easy, but it’s done. So let’s use it.


var distinctResult = MyEnumerable.Distinct(new SampleComparer());
.csharpcode, .csharpcode pre { font-size: small; color: black; font-family: consolas, “Courier New”, courier, monospace; background-color: #ffffff; /*white-space: pre;*/ } .csharpcode pre { margin: 0em; } .csharpcode .rem { color: #008000; } .csharpcode .kwrd { color: #0000ff; } .csharpcode .str { color: #006080; } .csharpcode .op { color: #0000c0; } .csharpcode .preproc { color: #cc6633; } .csharpcode .asp { background-color: #ffff00; } .csharpcode .html { color: #800000; } .csharpcode .attr { color: #ff0000; } .csharpcode .alt { background-color: #f4f4f4; width: 100%; margin: 0em; } .csharpcode .lnum { color: #606060; }


  Done, so now I just have my distinct results, right? NO. WHAT? WHY NOT?


  So I found out that Distinct isn’t really working, so what can I use? Why not GroupBy. 


  So I did the following code:


var distinctEntities = MyEnumerable.GroupBy(element => element.Name);


 Damn this gives me a IEnumerable<IGrouping<string, Element>> and I just want a list elements now.


  So there we go again:


var distinctEntities = MyEnumerable.GroupBy(element => element.Name)
  .Select(group => group.First());


  And now I have a real list of the distinct elements inside my IEnumerable..csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }



.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, “Courier New”, courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }

5 comments on “Distinct not working in Linq-to-Objects

  1. Does your object’s getHashCode implementation hash the Name field? That’s one reason the comparer wouldn’t work as expected.

    see:

    http://stackoverflow.com/questions/432829/c-distinct-on-ienumerablet-with-custom-iequalitycomparer

  2. Yes but the implementation of Distinct wasn’t looking at the GetHashCode. I had that, look at
    public int GetHashCode(MyObject obj)
    {
    return obj.GetHashCode();
    }

    that was implemented. So it should work. Right?

  3. MicioDue on said:

    Funny… I ran today into the same problem and I followed exactly your path, step by step, reaching the same conclusions! :-D

    Reading page 342 to 345 of J.Rattz’s “Pro Linq” it seems enough to specify DataRowComparer.Default as argument of .Distinct(), too bad it seems not to be enough….

  4. Patrik Akselsson on said:

    Remember, Select is not broken, and Distinct probably isnt either (http://pragprog.com/the-pragmatic-programmer/extracts/tips).

    An IEqualityProvider must return the same hash code for equal items (see http://msdn.microsoft.com/en-us/library/system.collections.iequalitycomparer.gethashcode.aspx). Your GetHashCode seem to use object.GetHashCode, which probably returns different values for all objects in your collection.

    Distinct would work if your GetHashCode-implementation was changed to:

    public int GetHashCode(MyObject obj){
    return obj.Id.GetHashCode();
    }

  5. Thanks, I’ll try that.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

* Copy This Password *

* Type Or Paste Password Here *

759 Spam Comments Blocked so far by Spam Free Wordpress

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>