2008-11-14 13 views
83

Ähnlich wie List<> OrderBy Alphabetical Order möchten wir nach einem Element sortieren, dann nach einem anderen. wir wollen das funktionale Äquivalent vonC# Liste <> Sortieren nach x dann y

SELECT * from Table ORDER BY x, y 

Wir haben eine Klasse erreichen, die eine Reihe von Sortierfunktionen enthalten, und wir haben keine Probleme durch ein Element zu sortieren.
Zum Beispiel:

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

List<MyClass> MyList; 

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

Und wir haben die folgenden 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 

Stable Art vorzuziehen wäre, aber nicht erforderlich. Die Lösung, die für .Net 2.0 funktioniert, ist willkommen.

+0

@Bolu Ich habe ausdrücklich helfen kann die Tag-Post-Version Agnostiker und aktualisiert Antworten zu machen, dass anzupassen. Ziehen Sie in Betracht, die Frage zu klären, anstatt das Tag wiederherzustellen, wenn Sie der Meinung sind, dass 4.0/2.0 nicht prominent genug ist. –

+0

Sorry @AlexeiLevenkov, hat nicht viel Aufmerksamkeit geschenkt, wenden Sie sich bitte an Rollback. – Bolu

+0

OK. Die Änderung rückgängig gemacht. –

Antwort

97

Denken Sie daran, dass Sie keine stabile Sortierung benötigen, wenn Sie alle Mitglieder vergleichen. Die 2.0-Lösung, wie gewünscht, kann wie folgt 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); 
    }); 
} 

Sie beachten Sie, dass diese 2.0-Lösung noch bevorzugt über die beliebte 3.5 Linq Lösung ist, es eine direkte Art führt und nicht über die O (n) Speicherbedarf des Linq-Ansatzes. Es sei denn, Sie bevorzugen, dass das ursprüngliche List-Objekt natürlich unberührt bleibt.

150

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

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

Hinweis: für .Net 2.0 (oder wenn Sie nicht LINQ) siehe Hans Passant answer zu dieser Frage.

+2

Von einem anderen Antwort Post von phoog hier: http://stackoverflow.com/questions/9285426/orderby-and-list-vs-iorderdenumerable Es erstellt eine andere Liste mit den ursprünglichen Elementen in einer neuen Reihenfolge. Dies ist nur nützlich, wenn Sie die ursprüngliche Reihenfolge für einen anderen Zweck beibehalten müssen. es ist eher verschwenderischer als das Sortieren der Liste an Ort und Stelle – dreamerkumar

+0

Achtung: ThenBy wird ausgewertet, auch wenn es nicht verwendet wird ... –

5

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

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; 
    } 
} 

I implementiert IComparable, so kann es unstabil durch List.Sort() sortiert werden.

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

Ich lieh mir diese Insertionsort Methode von C# 411:

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; 
      } 
    } 

du in der Sortier Helfer Klasse setzen würde, die Sie in Ihrer Frage erwähnt.

Nun, 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:

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

Dies ist wahrscheinlich mit einigen anonymen Delegierten gereinigt werden konnte, aber ich werde das für Sie überlassen.

EDIT: Und NoBugz demonstriert die Macht der anonymen Methoden ...Also, betrachte meine mehr oldschool: P

+0

Wow, danke Jonathan, darüber hinaus! –

1

Ich hatte ein Problem, bei dem OrderBy und ThenBy mir nicht das gewünschte Ergebnis gaben (oder ich wusste einfach nicht, wie man sie richtig benutzt).

Ich ging mit einer Liste. Lösung so etwas wie diese.

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))); 
Verwandte Themen