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.

War es hilfreich?

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());
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top