it-swarm.com.de

C # Liste <> Sortieren nach x, dann y

Ähnlich wie bei List <> OrderBy Alphabetical Order möchten wir nach einem Element und dann nach einem anderen sortieren. wir wollen das funktionale äquivalent von erreichen

SELECT * from Table ORDER BY x, y  

Wir haben eine Klasse, die eine Reihe von Sortierfunktionen enthält, und es gibt keine Probleme, nach einem Element zu sortieren.
Beispielsweise:

public class MyClass {
    public int x;
    public int y;
}  

List<MyClass> MyList;

public void SortList() {
    MyList.Sort( MySortingFunction );
}

Und wir haben Folgendes in der Liste:

Unsorted     Sorted(x)     Desired
---------    ---------    ---------
ID   x  y    ID   x  y    ID   x  y
[0]  0  1    [2]  0  2    [0]  0  1
[1]  1  1    [0]  0  1    [2]  0  2
[2]  0  2    [1]  1  1    [1]  1  1
[3]  1  2    [3]  1  2    [3]  1  2

Stabile Sortierung wäre vorzuziehen, aber nicht erforderlich. Eine Lösung, die für .NET 2.0 funktioniert, ist willkommen.

86
Byron Ross

Denken Sie daran, dass Sie keine stabile Sortierung benötigen, wenn Sie alle Mitglieder vergleichen. Die 2.0-Lösung kann wie gewünscht folgendermaßen aussehen:

 public void SortList() {
     MyList.Sort(delegate(MyClass a, MyClass b)
     {
         int xdiff = a.x.CompareTo(b.x);
         if (xdiff != 0) return xdiff;
         else return a.y.CompareTo(b.y);
     });
 }

Beachten Sie, dass diese 2.0-Lösung weiterhin der beliebten 3.5-Linq-Lösung vorzuziehen ist, eine direkte Sortierung durchführt und nicht die O(n) - Speicheranforderungen des Linq-Ansatzes erfüllt. Es sei denn, Sie möchten, dass das ursprüngliche List-Objekt unberührt bleibt.

98
Hans Passant

Für Versionen von .Net, in denen Sie LINQ OrderBy und ThenBy (oder ThenByDescending verwenden können, falls erforderlich):

using System.Linq;
....
List<SomeClass>() a;
List<SomeClass> b = a.OrderBy(x => x.x).ThenBy(x => x.y).ToList();

Hinweis: Informationen zu .NET 2.0 (oder wenn Sie LINQ nicht verwenden können) finden Sie unter Hans Passant-Antwort auf diese Frage.

154
Toby

Sie müssen die Schnittstelle IComparer implementieren. Hier ist ein guter Beitrag mit Beispielcode.

7
Bill the Lizard

Der Trick besteht darin, eine stabile Sortierung zu implementieren. Ich habe eine Widget-Klasse erstellt, die Ihre Testdaten enthalten kann:

public class Widget : IComparable
{
    int x;
    int y;
    public int X
    {
        get { return x; }
        set { x = value; }
    }

    public int Y
    {
        get { return y; }
        set { y = value; }
    }

    public Widget(int argx, int argy)
    {
        x = argx;
        y = argy;
    }

    public int CompareTo(object obj)
    {
        int result = 1;
        if (obj != null && obj is Widget)
        {
            Widget w = obj as Widget;
            result = this.X.CompareTo(w.X);
        }
        return result;
    }

    static public int Compare(Widget x, Widget y)
    {
        int result = 1;
        if (x != null && y != null)                
        {                
            result = x.CompareTo(y);
        }
        return result;
    }
}

Ich habe IComparable implementiert, damit es instabil nach List.Sort () sortiert werden kann.

Ich habe jedoch auch die statische Methode Compare implementiert, die als Delegat an eine Suchmethode übergeben werden kann.

Ich habe diese Einfügesortiermethode von C # 411 ausgeliehen:

 public static void InsertionSort<T>(IList<T> list, Comparison<T> comparison)
        {           
            int count = list.Count;
            for (int j = 1; j < count; j++)
            {
                T key = list[j];

                int i = j - 1;
                for (; i >= 0 && comparison(list[i], key) > 0; i--)
                {
                    list[i + 1] = list[i];
                }
                list[i + 1] = key;
            }
    }

Sie würden dies in die Klasse der Sortierhelfer aufnehmen, die Sie in Ihrer Frage erwähnt haben.

Nun, um es zu benutzen:

    static void Main(string[] args)
    {
        List<Widget> widgets = new List<Widget>();

        widgets.Add(new Widget(0, 1));
        widgets.Add(new Widget(1, 1));
        widgets.Add(new Widget(0, 2));
        widgets.Add(new Widget(1, 2));

        InsertionSort<Widget>(widgets, Widget.Compare);

        foreach (Widget w in widgets)
        {
            Console.WriteLine(w.X + ":" + w.Y);
        }
    }

Und es gibt aus:

0:1
0:2
1:1
1:2
Press any key to continue . . .

Dies könnte wahrscheinlich mit einigen anonymen Delegierten beseitigt werden, aber das überlasse ich Ihnen.

[~ # ~] edit [~ # ~] : Und NoBugz demonstriert die Kraft anonymer Methoden

5
FlySwat
4
Bala

Ich hatte ein Problem, bei dem OrderBy und ThenBy nicht das gewünschte Ergebnis lieferten (oder ich wusste einfach nicht, wie ich sie richtig verwenden sollte).

Ich ging mit einer Liste.Sort Lösung so etwas.

    var data = (from o in database.Orders Where o.ClientId.Equals(clientId) select new {
    OrderId = o.id,
    OrderDate = o.orderDate,
    OrderBoolean = (SomeClass.SomeFunction(o.orderBoolean) ? 1 : 0)
    });

    data.Sort((o1, o2) => (o2.OrderBoolean.CompareTo(o1.OrderBoolean) != 0
    o2.OrderBoolean.CompareTo(o1.OrderBoolean) : o1.OrderDate.Value.CompareTo(o2.OrderDate.Value)));
1
mofoo