2013-08-04 17 views
16
List<int> _lstNeedToOrder = new List<int>(); 
_lstNeedToOrder.AddRange(new int[] { 1, 5, 6, 8 }); 

//I need to sort this based on the below list. 

List<int> _lstOrdered = new List<int>();//to order by this list 
_lstOrdered.AddRange(new int[] { 13, 5, 11, 1, 4, 9, 2, 7, 12, 10, 3, 8, 6 }); 

order will be -->_lstNeedToOrder = 5,1,8,6 

Jak mogę to zrobić?Metoda LINQ do sortowania listy na podstawie większej listy

Odpowiedz

19

Dobrze prosty - ale nieefektywne - sposób byłoby:

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

Alternatywą byłoby wypracować daleko sposób uzyskania pożądanego indeks wartości. Jeśli twoje wartości zawsze będą w zakresie [1 ... n], możesz po prostu odwrócić tę "uporządkowaną listę" na "listę indeksów według wartości". W którym momencie można użyć:

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

(gdzie indexes miałoby dodatkową wartość na początku 0, tak aby rzeczy prostsze).

Alternatywnie można utworzyć wartość Dictionary<int, int> z indeksu. Byłoby to bardziej ogólne, ponieważ poradziłoby sobie z bardzo szerokim zakresem wartości bez zajmowania dużej ilości pamięci. Ale wyszukiwanie słownika jest oczywiście mniej wydajne niż wyszukiwanie tablicy lub listy.

Podobnie jak marginesie, które nie byłoby dobrze sformatować jako komentarz, twój inicjalizacji można uprościć stosując inicjator kolekcji:

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

Hej Jon, przepraszam Jeśli to głupie pytanie, ale dlaczego pierwszy nieefektywny? –

+1

@DimitarDimitrov: Używa 'IndexOf' do znalezienia żądanego indeksu każdego wpisu. Jest to operacja O (n) w rozmiarze '_lstOrdered', niepotrzebnie. –

+0

@DimitarDimitrov może dlatego, że użycie 'IndexOf'? –

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

Interesujący pomysł. Nie poradziłoby to z duplikatami, ale nie wiemy, czy to oczywiście konieczne. –

+0

Hm, nie myślałem o tej sprawie. :) Zgaduję, że zależy to od OP, czy to w wymaganiach, czy nie. –

+0

@VaughanHilts, nie będzie żadnych duplikatów w moim przypadku, dzięki! –

1

oszczędzania w pośrednim słowniku kolejność ...

// 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]); 

w .Sort metoda sortuje w miejscu tak _lstNeedToOrder zostaną uporządkowane.

4

można zbudować własny porównywarka takiego:

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

Teraz można powiedzieć

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

jak używać klasy 'SequenceComparer ', nie widzę jak jest używana w zapytaniu 'OrderBy'. –

+1

@ King King: Dzięki. Brakowało mi utworzenia go w wywołaniu 'OrderBy'. Jest tam teraz. Dzięki jeszcze raz. – jason

4

Działa to całkiem dobrze:

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

Inną opcją jest użycie Intersect, który gwarantuje zwrócenie elementów w kolejności, w jakiej występują w pierwszej kolejności.

Tak więc, w tym przykładzie

var result = _lstOrdered.Intersect(_lstNeedToOrder); 

daje { 5, 1, 8, 6} wymagane.

Powiązane problemy