2016-03-29 11 views
4

Ich habe eine List und ich habe die neue Reihenfolge, in der die List die Elemente in int[] haben soll ich, dass das Element will in List sollte gemäß dem Artikel in int[] nachbestellt werden. Hier ist mein Code, um das zu tun:Bestellliste von einer bestimmten Reihenfolge

class Program 
    { 
     static void Main(string[] args) 
     { 
      List<Test> tests = new List<Test>() { 
       new Test(){ No = 201 }, 
       new Test(){ No = 101 }, 
       new Test(){ No = 300 }, 
       new Test(){ No = 401 }, 
       new Test(){ No = 500 }, 
       new Test(){ No = 601 } 
      }; 


      int[] newOrder = new int[6] { 201, 401, 300, 101, 601, 500 }; 

      //after the opration the List should contain items in order 201, 401, 300, 101, 601, 500 

      List<Test> newTests = new List<Test>(); 

      foreach(var order in newOrder) 
      { 
       var item = tests.SingleOrDefault(t => t.No == order); 

       if (item != null) 
        newTests.Add(item); 
      } 


     } 

    } 

Das funktioniert gut. Aber es erstellt eine separate List und führt die Operation darauf aus. Gibt es einen besseren Weg, wo ich verwenden kann, kann gebaut werden. NET-Betrieb für diese oder kann die Operation auf dem gleichen List ohne Erstellen dieser Temp List etc?

Vielen Dank.

+0

prüfen Ende ab diesem http://stackoverflow.com/questions/3062513/how-can-i -sort-generic-list-desc-und-asc Oder Sie suchen nach [Kreuzung] (http://www.dotnetperls.com/intersect) –

+0

Wenn Sie in der gleichen Liste tun möchten, dann starten Sie die Elemente tauschen in der ursprünglichen Liste basierend auf dem Index des Ordnungsarrays. Es wird keinen Standardmechanismus geben –

+0

Sie können Ihr Array mit Ihrer Liste verbinden und dann 'Select' ohne Reihenfolge wählen. – Vahid

Antwort

5

Sie verbindet über die Leistung zu denken, wenn eine Art, wie diese ausgeführt wird. Wenn Sie nur eine Handvoll Elemente erwarten, ist Pedro's solution in Ordnung.

Wenn Sie viele Elemente (z. B. 100 oder 1000) erwarten, ist es keine gute Idee, die gesamte Sammlung tests für jedes Element in newOrder zu durchsuchen. In diesem Fall wäre es hilfreich, einen Dictionary für alle Index-/Sortierreihenfolgen-Lookups zu verwenden. Probieren Sie etwas wie folgt aus:

List<Test> tests = new List<Test>() { 
    new Test(){ No = 101 }, 
    new Test(){ No = 201 }, 
    new Test(){ No = 300 }, 
    new Test(){ No = 401 }, 
    new Test(){ No = 500 }, 
    new Test(){ No = 601 } 
}; 


int[] newOrder = new int[6] { 201, 401, 300, 101, 601, 500 }; 

// Create a Dictionary/hashtable so we don't have to search in newOrder repeatedly 
// It will look like this: { {201,0}, {401,1}, {300,2}, {101,3}, {601,4}, {500,5} } 
Dictionary<int, int> newOrderIndexedMap = Enumerable.Range(0, newOrder.Length - 1).ToDictionary(r => newOrder[r], r => r); 

// Order using 1 CPU 
var orderedTests = tests.OrderBy(test => newOrderIndexedMap[test.No]); 
// Order using multi-threading 
var orderedInParallelTests = tests.AsParallel().OrderBy(test => newOrderIndexedMap[test.No]); 

// Order using 1 CPU, when it's possible that a match will not be found in newOrder 
var orderedTestsSafe = tests.OrderBy(test => 
    { 
     int index; 
     bool foundIndex = newOrderIndexedMap.TryGetValue(test.No, out index); 
     return foundIndex ? index : Int32.MaxValue; 
    }); 

Beachten Sie, dass beide diese Antwort und Pedro davon aus, dass newOrder alle Werte in den tests Elemente und umgekehrt enthalten ist, enthält.

+0

Sie können die Abweichung zwischen Listen- und Array-Werten behandeln, indem Sie einen Standardwert verwenden die Nummer am Ende. Annahme, dass sie immer die gleichen im praktischen Fall fehlschlagen, in der Tat würde es für Liste mit mehr Anzahl von Elementen fehlschlagen –

+0

Wenn es möglich ist, dass einige Elemente von 'newOrder' fehlen, dann ist @ MrinalKamboj's Vorschlag richtig.In diesem Fall sollten Sie etwas wie 'orderedTestsSafe' verwenden. – Serge

+0

Verwenden Sie die Index-Map ist groß, aber jedes Element, das nicht mit der neuen Reihenfolgeliste übereinstimmt, wird aufgrund von 'Int32.MaxValue' als zufällig angeordnet, aber es wird möglicherweise nicht von OP benötigt. Gute Antwort – Eric

1
var newTesties= newOrder.Select(o => tests.First(t => t.No == o)); 

Grundsätzlich wähle ich jede Nummer 'o' in newOrder, und damit den entsprechenden Test abholen. Sie werden jedoch mit einer neuen Liste enden.

1

Versuchen Sie Ihr Array und Liste wie diese benötigen

newOrder.Join(tests, no => no, tst => tst.No, (no, tst) => tst) 
+0

Sehr gute Lösung, da es funktioniert, aber wenn die ursprüngliche Liste Zahlen enthält, die nicht Teil des Arrays sind, würde Left Outer Join eine bessere Wahl sein. –

1

Die Verwendung linker Verbindung kann eine der Möglichkeiten sein, die benutzerdefinierte Bestellung zu verwenden. Für jedes Element nicht auf die individuelle Bestellung entsprechen, verwenden ursprüngliche Reihenfolge der Liste am

var results = from a in tests.Select((r, i) => new {item = r, Index = i}) 
       // left join 
       from b in newOrder.Select((r, i) => new { item = r, Index = i }) 
           .Where(b => a.item.No == b.item).DefaultIfEmpty() 
       // Not in order list then use original ordering 
       orderby (b == null ? tests.Count() + a.Index : b.Index) 
       select a.item; 

.Net Fiddle

+0

Left Outer Join, Voila, dies behandelt das ganze Szenario –

Verwandte Themen