2013-01-09 14 views
6

Ho un elenco genericoOrdinamento di un elenco generico da parte di un ordinamento esterno

esempio semplificato

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

Quello che vorrei fare è quello di ordinare questi elementi sulla base di un elenco esterno ordinare

Nell'esempio

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

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

c'è qualcosa built-in per LINQ che mi potrebbe aiutare achi Eve questo o devo andare nel modo migliore?

+0

si desidera ordinare e tenerli in una sola lista o se tornare gruppi essere utile? – R0MANARMY

risposta

8

Con l'elenco è possibile utilizzare IndexOf per Enumerable.OrderBy:

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

Così l'indice della proroga nel sortList determina la priorità nell'altra lista. Le estensioni sconosciute hanno la massima priorità poiché il loro indice è -1.

ma è necessario aggiungere un punto per l'estensione per farlo funzionare:

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

Se questo non è un'opzione bisogna smanettare con Substring o Remove, ad esempio:

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

+1 per bella soluzione e dejavu :) –

+1

Basta notare che GetExtension() restituisce anche l'estensione "punto", mentre sortList non ce l'ha ... – digEmAll

+0

@digEmAll Ottiene l'estensione dai nomi di file nell'elenco originale (es. "lorem1.doc") –

6

Questa soluzione funzionerà anche se alcuni nomi di file non hanno estensioni:

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

Si potrebbe provare a utilizzare il metodo Array.indexOf():

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

Un sortDicionary sarebbe più efficiente:

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

In questo modo la ricerca è O(1) piuttosto che O(# of extensions).

Inoltre, se si dispone di un gran numero di nomi di file e un piccolo numero di estensioni, potrebbe in realtà essere più veloce di fare

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

Questo significa che le scale di ordinamento per il numero di estensioni distinte in ingresso, piuttosto che il numero di elementi nell'input.

Ciò consente anche di assegnare a due interni la stessa priorità.

0

Ecco un altro modo che non usa OrderBy:

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

nota che la complessità di questo approccio è O(n * m) con n = sortList.Count e m list.Count.

Il OrderBy approccio caso peggiore complessità è invece O(n * m * log m) ma probabilmente, in generale, sarà più veloce (in quanto IndexOf non si traduca sempre in O(n)).Tuttavia con il piccolo n e m non noterai alcuna differenza.

Per le grandi liste il modo più veloce (complessità O(n+m)) potrebbe essere la costruzione di una temporanea ricerca vale a dire:

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