简体   繁体   English

如何从C#中的LINQ查询中获取不同的项目?

[英]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. 我有一个查询,它的定义是这样的,我用它来生成JSON输出。 The point is that, I have applied Distinct method to it, but it still shows duplicate items. 关键是,我已经对其应用了Distinct方法,但是它仍然显示重复项。 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. 我想我需要以某种方式专门将Distinct应用于该值。

I suspect you need to switch your Distinct and Select calls. 我怀疑您需要切换“非Distinct和“ Select呼叫。 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. Distinct将比较比给定投影可能期望的更多字段,这可能意味着正在比实际要比较的字段进行比较。 Calling Select first will reduce the number of fields that are compared to generate the distinct list. 首先调用“ Select将减少进行比较以生成唯一列表的字段数。

ie

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();

.NET has no way of knowing how you want to determine "equality" in your objects. .NET无法知道您如何确定对象中的“平等”。 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() . 您可以为Distinct()提供一个自定义的相等比较器 For example, if you're just comparing on a .Name property to determine uniqueness, it might look something like this: 例如,如果您只是在比较.Name属性以确定唯一性,它可能看起来像这样:

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. 如果这种平等是核心业务逻辑,而不仅仅是在特定的比较中使用,则您甚至可以在Business本身上实现EqualsGetHashCode ,以便可以在其他地方使用平等比较。 Just be aware that could be a breaking change to existing code which already assumes referential equality. 请注意,这可能是对已经假定引用相等的现有代码的重大更改。

Business class needs to override object.Equals and object.GetHashCode methods and implemented IEquatable<T> before the Distinct method will function correctly. Business类需要重写object.Equalsobject.GetHashCode方法和实现IEquatable<T>前的Distinct方法将正常工作。

See MSDN examples: Enumerable.Distinct Method (IEnumerable) 请参见MSDN示例: Enumerable.Distinct方法(IEnumerable)

Distinct() returns distinct elements from a sequence by using the default equality comparer to compare values. 通过使用默认的相等比较器比较值, Distinct()返回序列中的不同元素。 so you should create BusinessEqualityComparer class should Implement IEqualityComparer Interface 因此,您应该创建BusinessEqualityComparer类,并应实现IEqualityComparer接口

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();
    }

.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. 不提供手动比较器的.Distinct()将使用已处理类型的默认比较器,该类型将最终使用您的Business类的.Equals().GetHashCode()

So unless you have overridden those methods .Distinct() will only remove reference-wise duplicates. 因此,除非您重写了这些方法, .Distinct()将仅删除引用方式的重复项。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM