Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Distinct not working with LINQ to Objects

class Program {     static void Main(string[] args)     {         List<Book> books = new List<Book>          {             new Book             {                 Name="C# in Depth",                 Authors = new List<Author>                 {                     new Author                      {                         FirstName = "Jon", LastName="Skeet"                     },                      new Author                      {                         FirstName = "Jon", LastName="Skeet"                     },                                        }             },             new Book             {                 Name="LINQ in Action",                 Authors = new List<Author>                 {                     new Author                      {                         FirstName = "Fabrice", LastName="Marguerie"                     },                      new Author                      {                         FirstName = "Steve", LastName="Eichert"                     },                      new Author                      {                         FirstName = "Jim", LastName="Wooley"                     },                 }             },         };           var temp = books.SelectMany(book => book.Authors).Distinct();         foreach (var author in temp)         {             Console.WriteLine(author.FirstName + " " + author.LastName);         }          Console.Read();     }  } public class Book {     public string Name { get; set; }     public List<Author> Authors { get; set; } } public class Author {     public string FirstName { get; set; }     public string LastName { get; set; }     public override bool Equals(object obj)     {         return true;         //if (obj.GetType() != typeof(Author)) return false;         //else return ((Author)obj).FirstName == this.FirstName && ((Author)obj).FirstName == this.LastName;     }  } 

This is based on an example in "LINQ in Action". Listing 4.16.

This prints Jon Skeet twice. Why? I have even tried overriding Equals method in Author class. Still Distinct does not seem to work. What am I missing?

Edit: I have added == and != operator overload too. Still no help.

 public static bool operator ==(Author a, Author b)     {         return true;     }     public static bool operator !=(Author a, Author b)     {         return false;     } 
like image 646
Tanmoy Avatar asked Sep 02 '09 03:09

Tanmoy


People also ask

Why distinct is not working in Linq?

LINQ Distinct is not that smart when it comes to custom objects. All it does is look at your list and see that it has two different objects (it doesn't care that they have the same values for the member fields). One workaround is to implement the IEquatable interface as shown here.

How does distinct work Linq?

LINQ Distinct operator removes all the duplicate values from the collection and finally returns the dissimilar or unique values. The LINQ Distinct operator available in only Method Syntax and it not supports the Query Syntax. LINQ Distinct is an operator which comes under Set Operator.

Does Linq distinct use equals?

c# - Linq distinct doesn't call Equals method - Stack Overflow. Stack Overflow for Teams – Start collaborating and sharing organizational knowledge.


1 Answers

LINQ Distinct is not that smart when it comes to custom objects.

All it does is look at your list and see that it has two different objects (it doesn't care that they have the same values for the member fields).

One workaround is to implement the IEquatable interface as shown here.

If you modify your Author class like so it should work.

public class Author : IEquatable<Author> {     public string FirstName { get; set; }     public string LastName { get; set; }      public bool Equals(Author other)     {         if (FirstName == other.FirstName && LastName == other.LastName)             return true;          return false;     }      public override int GetHashCode()     {         int hashFirstName = FirstName == null ? 0 : FirstName.GetHashCode();         int hashLastName = LastName == null ? 0 : LastName.GetHashCode();          return hashFirstName ^ hashLastName;     } } 

Try it as DotNetFiddle

like image 96
skalb Avatar answered Sep 18 '22 05:09

skalb