2012-04-20 28 views
8

W kółko napotykam ten problem: jak pogrupować listę obiektów według listy innych obiektów?Jak grupować według listy elementów?

Mam listę obiektów typu A, a każdy z tych obiektów ma właściwość (można nazwać ją ListProp), która również jest listą. ListProp ma elementy typu B. Istnieje wiele elementów typu A o identycznych B -obiektach w ListProp, ale odwołanie do właściwości właściwości różni się od elementu do elementu. Jak pogrupować te A -obiekty w najszybszy sposób, w którym obiekty w ListProp są identyczne?

Przykładowy kod:

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

Dlaczego ostatni powinien być w trzeciej grupie? Powinien być na początku, czy nie powinienem? – abatishchev

+0

Ponieważ liczba elementów powinna być taka sama jak również. 0,1! = 0,1,1 – germanSharper

+0

OK, który był niewłaściwą edycją. Wyczyść teraz. – abatishchev

Odpowiedz

6

Można wdrożyć IEqualityComparer<List<B>> i używać go w innym przeciążeniu 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(); 
    } 
} 

Następnie można użyć przeciążenie

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

Perfect! Wielkie dzięki :) Dlaczego zawsze zapominam o rzeczach: SequenceEquals i przy użyciu niestandardowego porównywalnika. Uratowałeś mi dzień, a zwłaszcza mój weekend;) – germanSharper

+0

Nie ma za co :) –

4

Spróbuj tego:

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

Będzie grupa przez 0,1; 0,1; 0,1; 0,1,1; 0,1 odpowiednio.

+0

dzięki za twoją myśl, ale to działa tylko dla przykładu. Moje obiekty są znacznie bardziej złożone, więc trudno byłoby to zrobić w ten sposób. Ale dla prostego podejścia jest to dobry pomysł. – germanSharper

+0

@germanSharper: Wiesz, że to brzmi jak obliczanie kodu haszującego z obiektu (cel ten sam jest twój: równy przez obiekty kryterium powinien zwracać taką samą wartość/hash-kod). Może to być lista lub klasa. W naszym systemie wspólnym podejściem jest ograniczenie znaczących właściwości: "A: B: C: D:". – abatishchev

+0

@germanSharper: Możesz także porównać oba rozwiązania: elementy ograniczające/łączące w niestandardowym narzędziu porównującym. Ma sens dla mnie – abatishchev

0

Chciałbym podejść do tego w następujący sposób:

  1. Associate każdy element dziecko (w nieruchomości ListProp) z jego rodzica
  2. Grupy rodzice przez dzieci
  3. Wyświetl wyniki

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()}); 
Powiązane problemy