LINQ GroupBy系列

时间:2011-11-15 15:12:17

标签: c# linq linq-to-objects

是否可以使用集合属性在LINQ中进行GroupBy?

e.g。

void Main()
{
    var t1 = new Test() { Children = new List<string>() { "one", "two" } };
    var t2 = new Test() { Children = new List<string>() { "one", "two" } };
    var t3 = new Test() { Children = new List<string>() { "one", "three" }        };

    var tests = new List<Test>() { t1, t2, t3 };
    var anon =  from t in tests
                select new
                {
                    Children = t.Children
                };

    anon.GroupBy(t => t.Children).Dump();
}

public class Test
{
    public List<string> Children {get;set;}
}

在这个例子中,我希望有两组:

  

键:List(){“one”,“two”}值:t1,t2

     

键:List(){“one”,“three”}值:t3

我的理解是,匿名类型不是通过引用进行比较,而是通过比较公共属性的相等性来进行比较。

但实际结果是三组:

  

键:List(){“one”,“two”}值:t1

     

键:List(){“one”,“two”}值:t2

     

键:List(){“one”,“three”}值:t3

如果无法做到这一点,有没有办法得到我想要的结果?

希望能清楚地解释清楚......

4 个答案:

答案 0 :(得分:4)

默认情况下,GroupBy在按列表分组(引用类型)时将使用引用相等。

由于每次都有新的列表实例,因此它们并不相同。

但是,GroupBy {{1}}允许您指定自定义overload,以便您可以实现自己的比较字符串列表的方式,例如。< / p>

为了实现这一点,这里有很多IEqualityComparer来比较两个列表。

答案 1 :(得分:2)

获得3个组的原因是因为List<T>实现了与默认引用相等的相等性,而不是考虑任何两个列表之间所包含元素的“序列相等性”。如果你想要这样的语义,你必须自己实现IEqualityComparer<IList<T>>(或类似的)并使用接受相等比较器的重载将其注入GroupBy查询。这是一个sample实现(对于数组,不是列表,但很容易适应)。

如果您对 set 相等感到满意(订单和重复项无关紧要),那么您很幸运:您可以直接使用HashSet<T>和提供的CreateSetComparer方法比较器实现:

  var t1 = new Test { Children = new HashSet<string> { "one", "two" } };
  var t2 = new Test { Children = new HashSet<string> { "one", "two" } };
  var t3 = new Test { Children = new HashSet<string> { "one", "three" } };

  var tests = new List<Test> { t1, t2, t3 };

  // Only two groups: { one, two } and { one, three }
  tests.GroupBy(t => t.Children, HashSet<string>.CreateSetComparer())
       .Dump();

答案 2 :(得分:0)

问题是列表并不完全相同。它正在比较分组的相等性,并且你有两个新的List<string>,它们并不完全相同。但是,您可以通过哈希代码加入字符串,这将产生正确的结果:

tests.GroupBy(t => String.Join(string.Empty, t.Children.Select(c => c.GetHashCode().ToString())));

答案 3 :(得分:0)

我认为没有内置的方法。

看看Jon Skeet的回答:

Any chance to get unique records using Linq (C#)?