2013-01-09 24 views
6

Mam listę rodzajoweSortowanie listy rodzajowe przez zewnętrznego porządku sortowania

przykład uproszczony

var list = new List<string>() 
    { 
    "lorem1.doc", 
    "lorem2.docx", 
    "lorem3.ppt", 
    "lorem4.pptx", 
    "lorem5.doc", 
    "lorem6.doc", 
    }; 

Co chciałbym zrobić, to uporządkować te elementy na podstawie listy zewnętrznej zamawiającego

W przykładzie

var sortList = new[] { "pptx", "ppt", "docx", "doc" }; 

// Or 
var sortList = new List<string>() { "pptx", "ppt", "docx", "doc" }; 

Czy jest coś wbudowanego w Linq, które może mi pomóc w achi Czy to w ogóle, czy muszę iść na foreach?

+0

chcesz je uporządkować i trzymać je w jednej listy lub grupy będzie Wracając być przydatne? – R0MANARMY

Odpowiedz

8

Z listy można użyć IndexOf dla Enumerable.OrderBy:

var sorted = list.OrderBy(s => sortList.IndexOf(Path.GetExtension(s))); 

więc indeks rozszerzenia w sortList określa priorytet w drugiej listy. Nieznane rozszerzenia mają najwyższy priorytet, ponieważ ich indeks to -1.

Ale trzeba dodać kropkę do przedłużenia, aby to działa:

var sortList = new List<string>() { ".pptx", ".ppt", ".docx", ".doc" }; 

Jeśli nie jest to opcja trzeba bawić się wokół z Substring lub Remove, na przykład:

var sorted = list.OrderBy(s => sortList.IndexOf(Path.GetExtension(s).Remove(0,1))); 
+3

+1 dla dobrego rozwiązania i dejavu :) –

+1

Po prostu zauważ, że GetExtension() zwraca również rozszerzenie "dot", podczas gdy sortList go nie ma ... – digEmAll

+0

@digEmAll Otrzymuje rozszerzenie z nazw plików na oryginalnej liście (np. "lorem1.doc") –

6

To rozwiązanie zadziała, nawet jeśli niektóre nazwy plików nie mają rozszerzeń:

var sortList = new List<string>() { "pptx", "ppt", "docx", "doc" }; 
var list = new List<string>() 
    { 
    "lorem1.doc", 
    "lorem2.docx", 
    "lorem3.ppt", 
    "lorem4.pptx", 
    "lorem5.doc", 
    "lorem6.doc", 
    }; 

var result = 
     list.OrderBy(f => sortList.IndexOf(Path.GetExtension(f).Replace(".",""))); 
1

można spróbować przy użyciu metody Array.IndexOf():

var sortedList = list.OrderBy(i => sortList.IndexOf(System.IO.Path.GetExtension(i))).ToList(); 
1

sortDicionary byłoby bardziej efektywne:

var sortDictionary = new Dictionary<string, int> { 
    { ".pptx", 0 }, 
    { ".ppt" , 1 }, 
    { ".docx", 2 }, 
    { ".doc" , 3 } }; 

var sortedList = list.OrderBy(i => { 
    var s = Path.GetExtension(i); 
    int rank; 
    if (sortDictionary.TryGetValue(s, out rank)) 
     return rank; 
    return int.MaxValue; // for unknown at end, or -1 for at start 
}); 

ten sposób wyszukiwania jest O(1) zamiast O(# of extensions).

Ponadto, jeśli masz dużą liczbę nazw i niewielką liczbę rozszerzeń, to może faktycznie być szybciej robić

var sortedList = list 
    .GroupBy(p => Path.GetExtension(p)) 
    .OrderBy(g => { 
     int rank; 
     if (sortDictionary.TryGetValue(g.Key, out rank)) 
      return rank; 
     return int.MaxValue; // for unknown at end, or -1 for at start 
    }) 
    .SelectMany(g => g); 

Oznacza to szalę Sortuj według liczby odrębnych rozszerzeń w wejściu, zamiast liczby elementów na wejściu.

Umożliwia to również nadanie dwóm rozszerzeniom tego samego priorytetu.

0

Oto kolejny sposób, który nie korzysta z OrderBy:

var res = 
sortList.SelectMany(x => list.Where(f => Path.GetExtension(f).EndsWith(x))); 

Należy zauważyć, że złożoność tego podejścia jest O(n * m) z n = sortList.Count i m list.Count.

OrderBy podejście najgorszym przypadku złożoność jest zamiast O(n * m * log m) ale prawdopodobnie w ogóle będzie to szybciej (od IndexOf nie powoduje zawsze O(n)).Jednak z małymi n i m nie zauważysz żadnej różnicy.

Dla dużych list najszybszym sposobem (złożoność O(n+m)) może być konstruowania tymczasowy odnośnika tj:

var lookup = list.ToLookup(x => Path.GetExtension(x).Remove(0,1)); 
var res = sortList.Where(x => lookup.Contains(x)).SelectMany(x => lookup[x]); 
Powiązane problemy