2013-05-22 9 views
6

Ich habe eine Liste von Objekten, die eine Eigenschaft Rank haben. Dies ist eine ganze Zahl.Wie kann ich sortieren, sondern Nullen an die Unterseite setzen?

Ich möchte nach Rang auf meiner Ansicht nach sortieren, aber wenn ich dies tun:

myObjects = myObjects.Orderby(r=>r.Rank); 

i erhalten alle der Nullen (diese Bedeutung haben nicht an der Spitze gesetzt) ​​

Ich möchte um 1 zu sortieren -> n, aber die Nullen müssen am Ende der Liste stehen.

Ich möchte es so effizient eine Art wie möglich sein, wie die Liste

Antwort

18

LINQ ist ziemlich lang:

myObjects = myObjects 
    .OrderBy(r => r.Rank == 0) //false before true 
    .ThenBy(r => r.Rank); 

Diese wird nicht tun eigentlich zwei volle Sorten. Es wird die beiden lambdas in eine einzelne Wörterbuchsortierung über die zwei Schlüssel kombinieren.

Wenn du mit dem nicht vertraut sind nicht so offensichtliche false -before- true der Regel können Sie die erste Lambda mit r => r.Rank == 0 ? 1 : 0 ersetzen - aber, wohl wissend, die false -before- true Regel wirklich überflüssig erscheinen lässt.

+0

ist es eine bessere Art und Weise, ohne zwei volle Sorten zu tun zu haben? – leora

+0

@leora: Siehe http://msmvps.com/blogs/jon_skeet/archive/2011/01/04/reimplementing-linq-to-objects-part-26a-iorderedenumerable.aspx (und die nachfolgenden Beiträge) für einige weitere Details –

+2

@leora: Dies führt nicht zu zwei vollständigen Sortierungen. "OrderBy/ThenBy" ist ziemlich schlau. Denken Sie daran, das Ergebnis eines Abfrageausdrucks ist * eine Abfrage *, nicht * die Berechnung der Ergebnisse der Abfrage *. Wenn die Abfrage ausgeführt wird, weiß die Abfrage, ob nach der OrderBy ein ThenBy vorhanden ist. –

6

Sie können einen benutzerdefinierten comparer (implementierende IComparer) erstellen und Nullen auf den Boden sortieren sind. Der Pseudo-Code wäre:

public class ZeroComparer : IComparer { 
    public int Compare(Object intA, Object intB) { 
     if(intA == 0 && intB != 0) 
      return -1; 
     if(intA != 0 && intB == 0) 
      return 1; 
     return int.Compare(intA, intB); 
    } 
} 

dann verwenden, wie:

var comparer = new ZeroComparer(); 
myObjects = myObjects.Orderby(r=>r.Rank, comparer); 

Ein kurzes Beispiel, wie benutzerdefinierten comparers verwenden:

Use own IComparer<T> with Linq OrderBy

1
myObjects = myObjects.Orderby(r => r.Rank == 0 ? int.MaxValue : r.Rank); 

zu behandeln der Fall Rank == int.MaxValue:

myObjects = myObjects.Orderby(r => r.Rank == 0 ? int.MaxValue : r.Rank - 1); 
+1

Was ist wenn 'int.MaxValue' ist ein gültiger Wert für 'Rank'? – svick

+1

Gute Bemerkung, also müssen wir '1' zu Rank in der Order-Klausel nehmen. Seed bearbeitete Frage. – polkduran

Verwandte Themen