2012-04-20 101 views
8

我一次又一次遇到这个问题:如何通过包含其他对象的列表来对一组对象进行分组?如何根据元素列表进行分组?

我有一个A类型的对象列表,每个对象都有一个属性(我们称之为ListProp),这也是一个列表。 ListProp具有B类型的元素。有A类型的多个元素具有相同的B-对象ListProp,但ListProp属性参考因元素而异。如何将这些A对象分组为最快的方式,B-ListProp中的对象是相同的?

示例代码:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var exampleList = new List<A> 
     { 
      // Should be in first group 
      new A { ListProp = new List<B> 
      { 
       new B { Prop = new C { Number = 0 }}, 
       new B { Prop = new C { Number = 1 }} 
      }}, 
      // Should be in first group 
      new A { ListProp = new List<B> 
      { 
       new B { Prop = new C { Number = 0 }}, 
       new B { Prop = new C { Number = 1 }} 
      }}, 
      // Should be in second group 
      new A { ListProp = new List<B> 
      { 
       new B { Prop = new C { Number = 0 }}, 
       new B { Prop = new C { Number = 1 }}, 
       new B { Prop = new C { Number = 1 }} 
      }}, 
      // Should be in third group 
      new A { ListProp = new List<B> 
      { 
       new B { Prop = new C { Number = 0 }}, 
       new B { Prop = new C { Number = 0 }} 
      }} 
     }; 

     // Doesn't work because the reference of ListProp is always different 
     var groupedExampleList = exampleList.GroupBy(x => x.ListProp); 
    } 
} 

class C 
{ 
    public int Number { get; set; } 
    public override bool Equals(object o) 
    { 
     if (o is C) 
      return Number.Equals(((C)o).Number); 
     else 
      return false; 
    } 
} 

class B 
{ 
    public C Prop { get; set; } 
} 

class A 
{ 
    public IList<B> ListProp { get; set; } 
} 
+1

为什么最后应该是在第三组?它应该在第一,我不应该? – abatishchev 2012-04-20 11:28:25

+0

因为元素的数量也应该相同。 0,1!= 0,1,1 – germanSharper 2012-04-20 11:45:16

+0

好吧,那是不正确的编辑。现在清除。 – abatishchev 2012-04-20 11:47:51

回答

6

您可以实施IEqualityComparer<List<B>>并在其他GroupBy过载中使用它。

public class ListOfBEqualityComparer : IEqualityComparer<List<B>> 
{ 
    public bool Equals(List<B> x, List<B> y) 
    { 
     // you can also implement IEqualityComparer<B> and use the overload 
     return x.SequenceEqual(y); 
    } 

    public int GetHashCode(List<B> obj) 
    { 
     //implementation of List<T> may not work for your situation 
     return obj.GetHashCode(); 
    } 
} 

然后你可以使用过载

var groupedExampleList = exampleList.GroupBy(x => x.ListProp, 
              new ListOfBEqualityComparer()); 
+0

完美!非常感谢:)为什么我总是忘记这些东西:SequenceEquals并使用自定义比较器。你节省了我的一天,尤其是我的周末;) – germanSharper 2012-04-20 12:01:58

+0

不客气:) – 2012-04-20 12:57:24

4

试试这个:

GroupBy(x => String.Join(",", x.ListProp)); 

它将按0,1; 0,1; 0,1; 0,1,1; 0,1相应。

+0

感谢您的想法,但这只适用于该示例。我的对象要复杂得多,所以用这种方法很难做到。但对于一个简单的方法,这是一个好主意。 – germanSharper 2012-04-20 11:50:36

+0

@germanSharper:你知道这听起来像是从一个对象计算一个散列码(目标同样是你的:等于一个条件对象应该返回一个相等的值/散列码)。它可能是一个列表或类。在我们的框架中,通用的方法是划定有意义的属性:“A:B:C:D:”。 – abatishchev 2012-04-20 12:18:12

+0

@germanSharper:您也可以比较两种解决方案:在自定义比较器中分隔/加入项目。对我有意义 – abatishchev 2012-04-20 12:19:01

0

我会处理这个方式如下:与其父

  • 集团

    1. 关联的每个子元素(在ListProp属性)父母按子女
    2. 计划结果

    var data = exampleList.SelectMany(a=>a.ListProp.Select(x=>new{Key = x.Prop.Number, Value = a})) 
          .GroupBy(x=>x.Key) 
          .Select(g=>new {Number = g.Key, Items = g.ToList()}); 
    
  • 相关问题