2012-04-20 12 views
8

Mi imbatto ancora e ancora su questo problema: come posso raggruppare un elenco di oggetti tramite un elenco contenente altri oggetti?Come posso raggruppare in base a un elenco di elementi?

Ho una lista di oggetti di tipo A e ognuno di questi oggetti ha una proprietà (chiamiamolo ListProp) che è anche una lista. ListProp ha elementi del tipo B. Esistono più elementi di tipo A con gli stessi oggetti B in ListProp, ma il riferimento di proprietà ListProp differisce da elemento a elemento. Come posso raggruppare questi oggetti A nel modo più rapido, dove gli oggetti B sono identici in ListProp?

codice di esempio:

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

Perché l'ultimo dovrebbe essere nel terzo gruppo? Dovrebbe essere in prima, non dovrei? – abatishchev

+0

Perché il numero di elementi dovrebbe essere lo stesso. 0,1! = 0,1,1 – germanSharper

+0

Ok questa è stata una modifica impropria. Chiaro ora – abatishchev

risposta

6

È possibile implementare IEqualityComparer<List<B>> e utilizzarlo nell'altro sovraccarico di 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(); 
    } 
} 

Quindi è possibile utilizzare l'overload

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

Perfetto! Grazie mille :) Perché dimentico sempre queste cose: SequenceEquals e usando un comparatore personalizzato. Hai salvato la mia giornata e soprattutto il mio fine settimana;) – germanSharper

+0

Prego :) –

4

Prova questa:

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

Sarà gruppo da 0,1; 0,1; 0,1; 0,1,1; 0,1 conseguenza.

+0

grazie per il tuo pensiero, ma questo funziona solo per l'esempio. I miei oggetti sono molto più complessi, quindi sarebbe difficile farlo in questo modo. Ma per un approccio semplice questa è una buona idea. – germanSharper

+0

@germanSharper: Sai, sembra un calcolo di un codice hash da un oggetto (lo scopo è lo stesso: uguale per un criterio, gli oggetti devono restituire un valore uguale/codice hash). Potrebbe essere una lista o una classe. Nel nostro quadro l'approccio comune è delimitare le proprietà significative: "A: B: C: D:". – abatishchev

+0

@germanSharper: puoi anche confrontare entrambe le soluzioni: delimitare/unire gli elementi all'interno del confronto personalizzato. Ha senso per me – abatishchev

0

vorrei affrontare questo seguente modo:

  1. associare ogni elemento figlio (in proprietà ListProp) con il suo genitore
  2. Gruppo i genitori dai bambini
  3. Proietta i risultati

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()}); 
Problemi correlati