Sort general list by external sort order

I have a general list

Simplified example

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

What I would like to do is sort these items based on the ordering of the external list

In the example

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

Is there anything built into linq that could help me achieve this, or do I need to go along the foreach path?

+6
source share
5 answers

In the list, you can use IndexOf for Enumerable.OrderBy :

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

Thus, the extension index in sortList determines the priority in another list. Unknown extensions have the highest priority since their index is -1.

But you need to add a point to the extension to make it work:

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

If this is not an option, you need to deal with Substring or Remove , for example:

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

This solution will work even if some file names do not have extensions:

 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(".",""))); 
+6
source

You can try using the Array.IndexOf () method:

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

A sortDicionary will be more efficient:

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

So the search is O(1) , not O(# of extensions) .

In addition, if you have a large number of file names and a small number of extensions, it may be faster to do

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

This means that the sorting scale depends on the number of individual extensions at the input, and not on the number of elements at the input.

It also allows you to specify two extensions with the same priority.

+1
source

Here's another way that OrderBy doesn't use:

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

Note that the complexity of this approach is O(n * m) with n = sortList.Count and m list.Count .

In the worst case, the OrderBy approach works like O(n * m * log m) , but it will probably be faster overall (since IndexOf does not always result in O(n) ). However, with small n and m you will not notice any difference.

For large lists, the fastest way ( O(n+m) complexity) can create a temporary search, i.e.

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

All Articles