【问题标题】:This code returns distinct values. However, what I want is to return a strongly typed collection as opposed to an anonymous type此代码返回不同的值。但是,我想要的是返回一个强类型集合而不是匿名类型
【发布时间】:2011-11-12 06:30:10
【问题描述】:

我有以下代码:

var foo = (from data in pivotedData.AsEnumerable()
                   select new
                   {
                     Group = data.Field<string>("Group_Number"),
                     Study = data.Field<string>("Study_Name")
                   }).Distinct();

正如预期的那样,这会返回不同的值。但是,我想要的是返回一个强类型集合而不是匿名类型,所以当我这样做时:

var foo = (from data in pivotedData.AsEnumerable()
                   select new BarObject
                   {
                     Group = data.Field<string>("Group_Number"),
                     Study = data.Field<string>("Study_Name")
                   }).Distinct();

这不会返回不同的值,而是将它们全部返回。有没有办法用实际对象做到这一点?

【问题讨论】:

  • 在你的类型上实现 Equals()GetHashCode()
  • @dlev GetHashCode 应该做什么?
  • @BrunoLM:例如阅读这个答案:stackoverflow.com/questions/6305324/… GetHashCode 应该在 Equals 也比较的所有字段上提供哈希码,并用于哈希表或字典以快速查找对象。
  • @Bruno Distinct 将尝试将每个对象放入哈希表中(并且将仅返回那些不存在的对象。)这意味着必须正确实现哈希码以确保相等的项目具有相同的哈希。否则,Equals()(可能)不会被调用,因为对象可能散列到不同的存储桶。

标签: c# linq


【解决方案1】:

试试这个:

var foo = (from data in pivotedData.AsEnumerable().Distinct()
                   select new BarObject
                   {
                     Group = data.Field<string>("Group_Number"),
                     Study = data.Field<string>("Study_Name")
                   });

【讨论】:

  • 可能是可能的,但它的语义不同。如果除了“组”和“研究”之外还有其他字段,可能会留下一些重复项。
  • 是的,还有其他字段。为了简洁起见,我省略了它们。我最初确实尝试过这种方法。还是谢谢。
【解决方案2】:

为了使Distinct()(和许多其他 LINQ 功能)工作,被比较的类(在您的示例中为 BarObject)必须实现实现 Equals()GetHashCode(),或者提供单独的 IEqualityComparer&lt;T&gt; 作为Distinct() 的参数。

许多 LINQ 方法利用 GetHashCode() 来提高性能,因为在内部它们将使用 Set&lt;T&gt; 之类的东西来保存唯一项,它使用散列进行 O(1) 查找。此外,GetHashCode() 可以快速告诉您两个对象是否可能 等价,哪些绝对不等价——当然,只要正确实现了GetHashCode()

因此,您应该使您打算在 LINQ 中比较的所有类都实现 Equals()GetHashCode() 以确保完整性,或者创建一个单独的 IEqualityComparer&lt;T&gt; 实现。

【讨论】:

  • 谢谢,这就是我所做的。如果我将对象存储在例如字典中,我认为 GetHashCode 更重要?
  • @Darren:GetHashCode() 是查看两个对象是否相等的一种非常快速的方法。这是因为任何两个等效对象都应该始终具有相同的哈希码。有许多 LINQ 方法利用哈希码进行处理并在内部使用集合或字典。因此,在使用 LINQ 时,两者都很重要。
  • @Darren:刚刚反编译 Distinct(),它确实在内部使用了一个利用散列的 Set
  • @Darren:看博文,Gage 提到过:blog.jordanterrell.com/post/…Distinct 需要 GetHashCode 才能正常工作。
【解决方案3】:

看起来Distinct 无法比较您的BarObject 对象。因此,它比较了它们的引用,当然它们都是彼此不同的,即使它们具有相同的内容。

因此,要么覆盖 Equals 方法,要么向 Distinct 提供自定义 EqualityComparer。请记住在实现Equals 时覆盖GetHashCode,否则如果您将对象放入字典或哈希表作为键(例如HashSet&lt;BarObject&gt;)会产生奇怪的结果。可能(不确切知道)Distinct 在内部使用哈希集。

HereGetHashCode 的良好实践集合。

【讨论】:

    【解决方案4】:

    您需要为BarObject 覆盖EqualsGetHashCode,因为EqualityComparer.Default&lt;BarObject&gt; 是引用相等,除非您提供了EqualsGetHashCode 的覆盖(这是Enumerable.Distinct&lt;BarObject&gt;(this IEnumerable&lt;BarObject&gt; source) 使用的)。或者,您可以将IEqualityComparer&lt;BarObject&gt; 传递给Enumerable.Distinct&lt;BarObject&gt;(this IEnumerable&lt;BarObject&gt;, IEqualityComparer&lt;BarObject&gt;)

    【讨论】:

      【解决方案5】:

      应该很简单:

      var foo = (from data in pivotedData.AsEnumerable()
                     select new
                     {
                       Group = data.Field<string>("Group_Number"),
                       Study = data.Field<string>("Study_Name")
                     }).Distinct().Select(x => new BarObject {
                       Group = x.Group,
                       Study = x.Study
                     });
      

      【讨论】:

        【解决方案6】:

        按照 dlev 的建议执行或使用:

        var foo = (from data in pivotedData.AsEnumerable()
                       select new BarObject
                       {
                         Group = data.Field<string>("Group_Number"),
                         Study = data.Field<string>("Study_Name")
                       }).GroupBy(x=>x.Group).Select(x=>x.FirstOrDefault())
        

        查看更多信息http://blog.jordanterrell.com/post/LINQ-Distinct()-does-not-work-as-expected.aspx

        【讨论】:

        • 那(在我看来)不是一个很好的解决方案,因为 Distinct 更快,并且只是为了满足操作人员的需要而设计的。然而,博客文章很有趣。看起来我假设 Distinct 在内部使用 HashSet&lt;&gt; 是对的。
        【解决方案7】:

        您想将 other overload 用于带有比较器的 Distinct()。然后你可以实现你自己的IEqualityComparer<BarObject>

        【讨论】:

          猜你喜欢
          • 2021-06-22
          • 1970-01-01
          • 1970-01-01
          • 2016-01-21
          • 1970-01-01
          • 1970-01-01
          • 2023-04-09
          • 1970-01-01
          • 2017-10-06
          相关资源
          最近更新 更多