1

I'm trying to order a set of files base on its file name. Input is a directory with files like:

f0.vesperdp
f1.vesperdp
f2.vesperdp
....
f9.vesperdp
f10.vesperdp
f11.vesperdp
f12.vesperdp

I've built this LINQ query to sort them:

if (Directory.Exists(path))
{
    var directoryInfo = new DirectoryInfo(path);
    var files = from file in directoryInfo.EnumerateFiles()

    .Where(f => f.Extension == PAGE_FILE_EXTENSION)
                orderby file.Name.Substring(1, file.Name.Length - 1) ascending
                select file.FullName;

    return files.ToArray<string>();
}

But they are returning like

f0.vesperdp
f1.vesperdp
f10.vesperdp
....
f19.vesperdp
f2.vesperdp
f20.vesperdp
f21.vesperdp

I need them to be sorted using natural order (from 0 to n as f0,f1,f2...,f9,f10,f11) how can fix my orderby filter to match this? Or if there's other way, how can I achieve that? Thanks in advance.

Erre Efe
  • 15,387
  • 10
  • 45
  • 77

3 Answers3

1

It is ordering the string correctly, you are going to have to pull just the number out, convert to Integer, then order. This is untested, but you get the idea:

public int GetInt(string filename)
{
    int idx = file.Name.IndexOf(".");
    if(idx < 0) throw new InvalidOperationException();
    return Convert.ToInt32(filename.SubString(1, file.Name.Length - (idx - 1)));
} 

Then your orderby part:

.Where(f => f.Extension == PAGE_FILE_EXTENSION)
    orderby GetInt(file.Name) ascending
    select file.FullName;
naspinski
  • 34,020
  • 36
  • 111
  • 167
1

Naspinski's correct in theory, but here's the solution in code.

if (Directory.Exists(path))
{
    var directoryInfo = new DirectoryInfo(path);
    var files = from file in directoryInfo.EnumerateFiles()

    .Where(f => f.Extension == PAGE_FILE_EXTENSION)
                orderby int.Parse(file.Name.Substring(1, file.Name.IndexOf('.')-1)) ascending
                select file.FullName;

    return files.ToArray<string>();
}

The order-by clause basically changes to pull everything between the leading 'f' and the first dot, which from your examples will be a number string, which is then parsed into an integer number and displayed.

KeithS
  • 70,210
  • 21
  • 112
  • 164
0

Just pull the int value out of the name and orderby using that value:

.Where(f => f.Extension == PAGE_FILE_EXTENSION)
        orderby int.Parse(file.Name.Substring(1, file.Name.Length -
                          file.Extension.Length-1)) ascending
        select file.FullName;
NominSim
  • 8,447
  • 3
  • 28
  • 38
  • This will throw an exception. You need to stop your parsing at the period. – jsmith Jul 23 '12 at 17:14
  • Won't work; file.Name includes the extension, so the substring being pulled from `f0.vesperdp` would be `0.vesperdp` which is non-numeric. – KeithS Jul 23 '12 at 17:15