2012-04-20 95 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()}); 
    
  • 相關問題