tett
tett

Reputation: 605

How to get distinct items from a LINQ query in C#?

I have a query, which is defined like this, and I used it to generate a JSON output. The point is that, I have applied Distinct method to it, but it still shows duplicate items. For example, I have many items with value "Unclassifed", whereas I want only one of it, same goes for some other values. Here is my query:

var results = db.Users.OfType<Business>()
              .Where(b => b.StateID == state && (term == null || b.Description.ToLower().Contains(term.ToLower())))
              .Distinct().Select(x => new { id = x.StateID, value = x.Description }).Take(5).ToList();

Any idea, how to fix it? I guess I need to specifically apply Distinct to the value somehow.

Upvotes: 0

Views: 113

Answers (5)

Daniel Kelley
Daniel Kelley

Reputation: 7747

I suspect you need to switch your Distinct and Select calls. Distinct will compare more fields than you are probably expecting given your projection, which may mean fields other than the ones you actually want to compare on are being compared. Calling Select first will reduce the number of fields that are compared to generate the distinct list.

i.e.

var results = db.Users.OfType<Business>()
          .Where(b => b.StateID == state && (term == null ||  b.Description.ToLower().Contains(term.ToLower())))
          .Select(x => new { id = x.StateID, value = x.Description })
          .Distinct()
          .Take(5)
          .ToList();

Upvotes: 4

RaphM
RaphM

Reputation: 91

.Distinct() without providing a manual comparer will use the default comparer of the processed type which will ultimately use the .Equals() and .GetHashCode() of your Business class.

So unless you have overridden those methods .Distinct() will only remove reference-wise duplicates.

Upvotes: 0

David
David

Reputation: 219057

.NET has no way of knowing how you want to determine "equality" in your objects. By default, equality of reference types is based only on reference equality, so all of your objects are already distinct by default.

You can provide a custom equality comparer to Distinct(). For example, if you're just comparing on a .Name property to determine uniqueness, it might look something like this:

class BusinessComparer : IEqualityComparer<Business>
{
    public bool Equals(Business x, Business y)
    {
        if (Object.ReferenceEquals(x, y))
            return true;
        if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
            return false;
        return x.Name == y.Name;
    }

    public int GetHashCode(Business business)
    {
        if (Object.ReferenceEquals(business, null))
            return 0;
        int hashBusinessName = business.Name == null ? 0 : business.Name.GetHashCode();
        return hashProductName;
    }
}

If this equality is core business logic and not just used in this particular comparison then you might even implement Equals and GetHashCode on Business itself so that equality comparison can be used elsewhere. Just be aware that could be a breaking change to existing code which already assumes referential equality.

Upvotes: 1

BRAHIM Kamel
BRAHIM Kamel

Reputation: 13794

Distinct() returns distinct elements from a sequence by using the default equality comparer to compare values. so you should create BusinessEqualityComparer class should Implement IEqualityComparer Interface

class BusinessEqualityComparer : IEqualityComparer<Business>
{

    public bool Equals(Business b1, Business b2)
    {
        if (b1.ID == b2.ID)
        {
            return true;
        }
        else
        {
            return false;
        }
    }


    public int GetHashCode(Business business)
    {
        int hCode = business.ID ^ business.ID ^ business.ID;
        return hCode.GetHashCode();
    }

Upvotes: 0

toadflakz
toadflakz

Reputation: 7934

Business class needs to override object.Equals and object.GetHashCode methods and implemented IEquatable<T> before the Distinct method will function correctly.

See MSDN examples: Enumerable.Distinct Method (IEnumerable)

Upvotes: 0

Related Questions