tags:

views:

469

answers:

5

I decided to rephrase my question. 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.

Sorry for the confusion.

A: 

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
+3  A: 
//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
@Yann Schwartz: Those were just mock file names, the alphabetical key i want to use is the first letter of the file. Thanks!
Chris
Sorry. I thought you wanted a custom alphabetical order (I've seen stranger things :-) )
Yann Schwartz
euh that isn't what he wants? I thought he wanted that as well..
Thomas Stock
@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
Yes, this works. +1
David B
@Yann: Yes, your answer is awesome, and after a bit of messaging, it worked great! Thanks!
Chris
A: 
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
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))
David B
+2  A: 

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();
David B
+1  A: 

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