8

I have over a thousand folders, each folder contains one or more files with the following names:

Unordered:

Alison.ext
Heather.ext
Molly.ext
Paula.ext
Sam.ext

Ordered:

Molly.ext
Sam.ext
Heather.ext
Alison.ext
Paula.ext

I would like to write an expression to sort this list as described above.

gunr2171
  • 16,104
  • 25
  • 61
  • 88
Chris
  • 6,702
  • 8
  • 44
  • 60

5 Answers5

14
//Creating a dictionary with the custom order
var order = "MSHAP";
var orderDict = order.Select((c,i)=>new {Letter=c, Order=i})
                     .ToDictionary(o => o.Letter, o => o.Order);

var list = new List<string>{"A.ext", "H.ext", "M.ext", "P.ext", "S.ext"};

//Ordering by the custom criteria
var result = list.OrderBy(item => orderDict[item[0]]);

Instead of calling orderDict[item[0]] you could have a nice helper method that cares for the fringe cases (non existent letters, null, and so on). But that's the idea.

Yann Schwartz
  • 5,954
  • 24
  • 27
  • @Yann Schwartz: Those were just mock file names, the alphabetical key i want to use is the first letter of the file. Thanks! – Chris Jun 02 '09 at 21:51
  • Sorry. I thought you wanted a custom alphabetical order (I've seen stranger things :-) ) – Yann Schwartz Jun 02 '09 at 21:54
  • @Chris: After reading the edit, I stand on my answer : it works as you require (it sorts based on the first letter, with a custom order, M first, then S, and so on) Try it on your own. – Yann Schwartz Jun 02 '09 at 22:18
  • @Yann: Yes, your answer is awesome, and after a bit of messaging, it worked great! Thanks! – Chris Jun 10 '09 at 16:35
6

Here's a method that produces keys for ordering

public int OrderKey(string fileName)
{
  char first = fileName[0];
  int result =
     first  == 'M' ? 1 :
     first  == 'S' ? 2 :
     first  == 'H' ? 3 :
     first  == 'A' ? 4 :
     first  == 'P' ? 5 :
     6;
  return result;
}

Here's how to call it:

List<File> ordered = Files.OrderBy(f => OrderKey(f.FileName)).ToList();
Amy B
  • 108,202
  • 21
  • 135
  • 185
  • Thx, worked perfectly. Had to order string codes(sightly modified to use string not char). Had to sort in rank, not alpha. And even catches codes that are not in the list, placing them last. – Yogurt The Wise Jul 18 '13 at 17:29
1
List<char> sortKeys = new List<char> { 'M', 'S', 'H', 'A', 'P' };
sortKeys.Reverse();
List<FileInfo> files = new List<FileInfo>(6);

foreach(char sortKey in sortKeys)
{
    var topFiles = files.Where(file => file.Name.StartsWith(sortKey.ToString()));
    var remainingFiles = files.Except(topFiles);
    files = topFiles.Concat(remainingFiles).ToList();
}

Untested and I'm sure there are faster ways, but at least it's with linq stuff as you asked :-)

edit: I just saw the edit on your post and now I don't have any idea anymore what you really want to do, so my code is probably useless to you..

Thomas Stock
  • 10,927
  • 14
  • 62
  • 79
  • The intent here is sound. It is questionable performance to enumerate the collection once per ordering key. Also, it is scary to consider Linq's deferred execution and the interaction of Concat and Except. topFiles.Concat(files.Except(topFiles)) – Amy B Jun 02 '09 at 22:26
0

You didn't mention exactly what sort of objects you have in the list, but let's say it's some generic arrangement like so:

public class File {
  public string FileName { ... }
  public long FileSize { ... }
  /* elided */
}

Then, given an IEnumerable called, say, files, you can just do:

var result = files.OrderBy(f => f.FileName);
John Feminella
  • 303,634
  • 46
  • 339
  • 357
0

You can store the desired order list in an array

int[] iIndex = {3,2,0,4, 1};

Say str holds your unordered List

List<string> str = new List<string>();
str.Add("Alison.ext");
str.Add("Heather.ext");
.
.
.

Add your list and corresponding order into a datatable

DataTable dt = new DataTable();
                dt.Columns.Add("Order", typeof(Int32));
                dt.Columns.Add("Name");

                for (int iCount =0; iCount< str.Count ; iCount ++)
                { 
                    DataRow drow1 = dt.NewRow();
                    drow1[0] = iIndex[iCount];
                    drow1[1] = str[iCount];
                    dt.Rows.Add(drow1);

                }
                dt.AcceptChanges();

Fynally Order yuor list to get yuor expected list

 var result = from ls in dt.AsEnumerable()
                         orderby ls.Field<int>("Order")
                         select ls;      
miti737
  • 471
  • 2
  • 7
  • 18