2013-08-04 3 views

Antwort

19

Nun, die einfachen - aber ineffizient - Weg wäre:

var result = _lstNeedToOrder.OrderBy(x => _lstOrdered.IndexOf(x)); 

Eine Alternative wäre, eine zu erarbeiten weit Weg, um den gewünschten Index eines Wertes zu erhalten. Wenn Ihre Werte immer im Bereich [1 ... n] liegen, können Sie diese "geordnete" Liste einfach als "Indexliste nach Wert" umkehren. An welcher Stelle Sie verwenden:

var result = _lstNeedToOrder.OrderBy(x => indexes[x]); 

(wo indexes einen zusätzlichen Wert zu Beginn für 0 haben würde, nur um die Dinge einfacher).

Alternativ können Sie einen Dictionary<int, int> von Wert zu Index erstellen. Das wäre allgemeiner, da es einen sehr großen Bereich von Werten handhaben würde, ohne viel Speicher zu beanspruchen. Aber eine Wörterbuchsuche ist offensichtlich weniger effizient als eine Array- oder Listensuche.

var listToOrder = new List<int> { 1, 5, 6, 8 }; 
var orderedList = new List<int> { 13, 5, 11, 1, 4, 9, 2, 7, 12, 10, 3, 8, 6 }; 
+0

Hey Jon, tut mir leid Wenn es eine dumme Frage ist, aber warum ist die erste ineffizient? –

+1

@DimitarDimitrov: Es verwendet 'IndexOf', um den gewünschten Index für jeden Eintrag zu finden. Das ist eine O (n) -Operation in der Größe von '_lstOrdered', unnötig. –

+0

@DimitarDimitrov vielleicht wegen der Verwendung von 'IndexOf'? –

13
List<int> results = _lstOrdered.Where(item => _lstNeedToOrder.Contains(item)).ToList(); 
+0

Interessante Idee. Es würde nicht mit Duplikaten umgehen, aber wir wissen nicht, ob das natürlich erforderlich ist. –

+0

Hm, ich hatte nicht an diesen Fall gedacht. :) Ich denke, es liegt am OP, ob das in den Anforderungen liegt oder nicht. –

+0

@VaughanHilts, es wird keine Duplikate in meinem Fall geben, Danke! –

1

Speicher in einem Zwischen Wörterbuch

die Reihenfolge ...:

nur als Randnotiz, die als Kommentar nicht gut formatiert werden würde, können Sie Ihre Initialisierung mit einer Auflistungsinitialisierer vereinfacht werden

// dict key will be the values of _lstOrdered, value will be the index of the 
// key in _lstOrdered 
// I'm using a seldom used .Select overload that returns the current value 
// plus its index (ix) 
var dict = _lstOrdered.Select((p, ix) => new { Value = p, Ix = ix }) 
         .ToDictionary(p => p.Value, p => p.Ix); 

// note that this will explode if _lstNeedToOrder contains values outside 
// _lstOrdered. 
_lstNeedToOrder.Sort((p, q) => dict[p] - dict[q]); 

Die Methode .Sort wird direkt sortiert, sodass _lstNeedToOrder bestellt wird.

4

Sie können einen benutzerdefinierten comparer wie diese bauen:

public class SequenceComparer<T> : IComparer<T> { 
    private readonly Dictionary<T, int> indexes; 

    public SequenceComparer(IEnumerable<T> sequence) { 
     this.indexes = 
      sequence 
       .Select((item, index) => new { Item = item, Index = index }) 
       .ToDictionary(x => x.Item, x => x.Index); 
    } 

    public int Compare(T x, T y) { 
     return indexes[x].CompareTo(indexes[y]); 
    } 
} 

Jetzt können Sie

var result = _lstNeedToOrder.OrderBy(x => x, new SequenceComparer(_lstOrdered)); 
+0

Wie verwende ich die Klasse 'SequenceComparer ', ich sehe nicht, wie es in der 'OrderBy' Abfrage verwendet wird. –

+1

@ König King: Danke. Ich habe es beim Aufruf von 'OrderBy' vermisst. Es ist jetzt da. Danke noch einmal. – jason

4

sagen Das funktioniert ganz gut:

var lookup = _lstOrdered 
    .Select((x, n) => new { x, n }) 
    .ToLookup(x => x.x, x => x.n); 

var query = 
    from x in _lstNeedToOrder 
    let rank = lookup[x] 
     .DefaultIfEmpty(int.MaxValue) 
     .First() 
    orderby rank 
    select x; 
2

Eine weitere Option ist Intersect zu verwenden, Dies garantiert, Elemente in der Reihenfolge zurückzugeben, in der sie in der ersten Sequenz erscheinen.

So, in diesem Beispiel

var result = _lstOrdered.Intersect(_lstNeedToOrder); 

ergibt { 5, 1, 8, 6} nach Bedarf.

Verwandte Themen