2015-02-27 12 views
10

Ich habe ein Objekt mit einer Nullable Int Eigenschaft "GroupId".Linq GroupBy mit jedem Nullwert als Gruppe

Mit einer Liste dieses Objekts möchte ich eine GroupBy auf dieser "GroupId" machen. Aber wenn ich es mache, bilden alle Nullwerte eine Gruppe.

Beispiel:

Objekt 1: GroupId: NULL

Objekt 2: GroupId: NULL

Objekt 3: GroupId: 1

Objekt 4: GroupId: 1

Objekt 5: GroupId: 2

Objekt 6: Grou pId: 2

MyList.GroupBy(f => f.GroupId, key => new {Object = key}); 

Ich werde 3 Gruppen bekommen.

Wie kann ich stattdessen 4 Gruppen bekommen? Eine Gruppe für jeden Wert NULL ...

+0

(Filter mit nicht null und dann die Gruppe gelten durch GroupId) union (Filter mit null und Gruppe von Primärschlüssel gelten). –

+0

@JenishRabadiya Beachten Sie, dass die 'GroupBy' die Reihenfolge der Elemente/Gruppen beibehält, während Ihre Lösung die Reihenfolge zerstört. – xanatos

+0

@xanatos hmm .. du bist richtig. –

Antwort

9

Dies ist wahrscheinlich die kürzeste Lösung:

var grouped = MyList.GroupBy(f => f.GroupId != null ? (object)f.GroupId : new object(), key => new { Object = key }); 

Beachten Sie, dass der „Schlüssel“ der Gruppen von object Typ sein. Für null Elemente erstelle ich ein neues "leeres" object. Der Gleichheitsvergleich von Objekten wird so aussehen, dass sie alle verschieden sind. Für Nicht-Null-Zahlen boxe ich sie einfach in ein Objekt. Boxed Integers pflegen den Gleichheitsoperator. Also:

new object().Equals(new object()) == false // always 

und

((object)1).Equals((object)1) == true // always 

und

((object)1).Equals((object)2) == false // always 

eine richtige Lösung wäre die Implementierung eines IEqualityComparer<int?>

public class MyComparer : IEqualityComparer<int?> { 
    public bool Equals(int? x, int? y) { 
     if (x == null || y == null) { 
      return false; 
     } 

     return x.Value == y.Value; 
    } 

    public int GetHashCode(int? obj) { 
     return obj.GetHashCode(); // Works even if obj is null :-) 
    } 
} 

und dessen Verwendung:

var grouped2 = MyList.GroupBy(f => f.GroupId, key => new { Object = key }, new MyComparer()); 
+2

'(Objekt) 1 == (Objekt) 1 'immer falsch. '(Objekt) == (Objekt)' ist Referenzgleichheit, es ruft nicht nach 'object.Equals' auf. – PetSerAl

+0

@PetSerAl Sie haben Recht. Verwirrt == mit Equals – xanatos

2

Generische Comparer, die ohne Boxen verwendet werden können.

public class NullableComparer<T> : IEqualityComparer<T?> 
     where T : struct 
{ 
    public bool Equals(T? x, T? y) 
    { 
     if (x == null || y == null) 
     { 
      return false; 
     } 

     return x.Equals(y); 
    } 

    public int GetHashCode(T? obj) 
    { 
     return obj.GetHashCode(); 
    } 
} 

Sie würden dann verwenden Sie es mögen:

// where GroupId as a nullable Guid 
var grouped = MyList.GroupBy(f => f.GroupId, new NullableComparer<Guid>());