Selektive Bestellung mit Linq, teilweise Bestellung
Frage
Nehmen wir an, ich habe eine Liste von Objekten:
var items = new {
new { Order = 0 },
new { Order = 1 },
new { Order = -1 },
new { Order = 3 },
new { Order = 2 },
new { Order = -1 }
};
Ich muss es bestellen, damit Artikel mit Order > -1
ganz oben auf der Liste stehen, die in aufsteigender Bestellung bestellt und verbleibende Elemente mit Order == -1
folgten ihnen.
Gibt es eine elegantere Art, dies zu tun, als dies zu verwenden? Conact()
und Where()
Klauseln:
var orderedItems = items.Where(x => x.Order > -1).OrderBy(x => x.Order)
.Conact(items.Where(x => x.Order == -1);
Damit würde nach dem Sortieren dieser Liste so aussehen:
var items = new {
new { Order = 0 },
new { Order = 1 },
new { Order = 2 },
new { Order = 3 },
new { Order = -1 },
new { Order = -1 }
};
Ebenfalls items
Die Liste im tatsächlichen Szenario ist bereits ein Komplex IQueryable<T>
Objekt. Deshalb versuche ich, die optimalste Möglichkeit zu finden, eine solch selektive Ordnung zu machen.
Lösung
Sie könnten dies versuchen - es erzeugt das Ergebnis, das Sie erwarten:
items.OrderBy(x.Order => x.Order == -1).ThenBy(x.Order => x.Order);
Andere Tipps
Wie Mike erwähnte, würde es in Ihrem Beispiel automatisch funktionieren, aber wir wollten zuerst alle -1 -Elemente bekommen und dann verbleibende Elemente in einer absteigenden Reihenfolge sortieren. Dies kann mit einem schönen Trick durchgeführt werden. Sie können mehrere Schlüssel verwenden, um Elemente zu bestellen. Der erste Schlüssel kann ein boolescher Wert sein, der sein wird false
für alle -1 -Werte (so werden sie zuerst sein) und true
Für alle anderen Werte (so dass sie nicht neu bestellt werden). Der zweite Schlüssel kann alles sein, was Sie die verbleibenden Elemente bestellen möchten. Zum Beispiel:
var nums = new int[] { -1, 4, 2, 3, -1, 4, 7 };
var q = from n in nums
orderby n != -1, n descending
select n;
Es wird zuerst alle Werte ergeben, für die n != -1
ist false
und dann alle Elemente, die bestellt wurden n descending
Also wirst du:
-1, -1, 7, 4, 4, 3, 2
Dies funktioniert im Allgemeinen, wenn Sie einige Elemente vor allem in der Bestellung behandeln müssen. Sie müssen nur die richtigen Bestellschlüssel bereitstellen.
Wenn Sie durch Aufstieg bestellen, sollte -1 bereits ganz oben auf der Liste stehen, da es sich um den kleinsten Wert handelt.
Wenn Sie jedoch immer noch unterschiedliche Sortierungen für Teilmengen der Daten anwenden wollten, denke ich nicht, dass es einen eleganteren Weg gibt, denn genau das tun Sie und die Gewerkschaft ist logisch korrekt. Sie versuchen, zwei separate Teilmengen der Daten herauszuziehen, sie anders zu sortieren und sie dann zusammenzuführen, was eines der Dinge ist, für die ich Vereinigung verwendet werden soll.
Auch ein benutzerdefinierter Vergleich hier, wenn Sie möchten, dass -1 zuerst erscheint, aber der Rest ist absteigend , aber irgendwie finde ich es eleganter :) Beachten Sie, dass es für INTs gemacht ist
class Comparer : IComparer<int>
{
public int Compare(int x, int y)
{
if (x == -1 || y == -1) return x - y;
return y - x;
}
}
OrderBy(x => x.Order < 0 ? int.MaxValue : x.Order)
oder wenn Sie die negativen Werte in absteigender Reihenfolge bestellen müssen
OrderBy(x => x.Order < 0 ? (long)int.MaxValue - x.Order : (long)x.Order)
Verwenden ein benutzerdefinierter Vergleich Um die gewünschte Bestellung zu definieren.
public class MyComparer : IComparer<int>
{
public int Compare(int a, int b)
{
if ((a < 0) && (b >= 0))
{
return 1;
}
if ((a >= 0) && (b < 0))
{
return -1;
}
return int.Compare(a, b);
}
}
Dann könnten Sie tun:
var orderedItems = items.OrderBy(x => x.Order, new MyComparer());