1

I am saving my image files in the following format: 1-6784 (1 being the sort order that I want to see and 6784 being a randomly generated number between 1000 and 9999.

When I look at the folder through explorer and arrange by name they all look fine and sorted according to the first number i.e. (1-XXXX, 2-XXXX , 9-XXXX, 12-XXXX etc.) in ascending order.

However when I get the FileInfo array for this directory it automatically sorts it by name I presume, but it for some reason would place 10-XXXX and 11-XXXX before 1-XXXX, 2-XXXX etc. So up until 10 it's fine and the order retains when image src links are generated in the view in my web application, but once I upload\save more than 9 files the double digit 10, 11 etc. take front spots in the array over the single digit numbers.

DirectoryInfo sourceDir = new DirectoryInfo(System.Web.HttpContext.Current.Request.MapPath("~/Content/ProductImages/" + Model.Products[i].ProductID.ToString() + "/thumbs/"));

                   if (sourceDir.Exists)
                   {

                       FileInfo[] fileEntries = sourceDir.GetFiles();
                       Array.Sort(fileEntries, (f1, f2) => f1.Name.CompareTo(f2.Name));


}

6 Answers 6

4

Description

You sort a string and this is the right result.

That is lexicographic sorting which means basically the language treats the variables as strings and compares character by character ("200" is greater than "19999" because '2' is greater than '1') ...

Source Why do some sorting methods sort by 1, 10, 2, 3…?

Solution

I suggest you create a custom Comparer which pads leading zeros to the fileName.

public class MyCustomComparer : IComparer<FileInfo>
{
    public int Compare(FileInfo x, FileInfo y)
    {
        // split filename
        string[] parts1 = x.Name.Split('-');
        string[] parts2 = y.Name.Split('-');

        // calculate how much leading zeros we need
        int toPad1 = 10 - parts1[0].Length;
        int toPad2 = 10 - parts2[0].Length;

        // add the zeros, only for sorting
        parts1[0] = parts1[0].Insert(0, new String('0', toPad1));
        parts2[0] = parts2[0].Insert(0, new String('0', toPad2));

        // create the comparable string
        string toCompare1 = string.Join("", parts1);
        string toCompare2 = string.Join("", parts2);

        // compare
        return toCompare1.CompareTo(toCompare2);
    }
}

And call them

FileInfo[] fileEntries = sourceDir.GetFiles();
Array.Sort(fileEntries, new MyCustomComparer());

More Information

Sign up to request clarification or add additional context in comments.

1 Comment

So I would somehow need to convert the sortorder to int and sort by that. Any quick and graceful way of doing that in my case?
3

You need to pad your sort order with leading zeros:

0001-XXX
0002-XXX
...

Or you may try the following to sort your exiting files:

FileInfo[] fileEntries = sourceDir.GetFiles()
   .OrderBy(f => Regex.Match(f.Name, "^[0-9]+").Value.PadLeft(10, '0'))
   .ToArray();

Comments

1

The reason is clear: the file name is a string, and as a string "11" comes after "1" but before "2".

In order to do what you want, in your comparison function you will need to parse the name and compare parts (separated by dash) as numbers (simply cast and compare)

Comments

1

You could parse out the numbers and compare them as follows:

DirectoryInfo sourceDir = new DirectoryInfo(System.Web.HttpContext.Current.Request.MapPath("~/Content/ProductImages/" + Model.Products[i].ProductID.ToString() + "/thumbs/"));

if (sourceDir.Exists)
{
    FileInfo[] fileEntries = sourceDir.GetFiles();
    Array.Sort(fileEntries,
        delegate(FileInfo x, FileInfo y)
        {
            String[] xvals = x.Name.Split('-');
            String[] yvals = y.Name.Split('-');

            int cmp = Int32.Parse(xvals[0]).CompareTo(Int32.Parse(yvals[0]));
            if (cmp != 0)
            {
                return cmp;
            }

            cmp = Int32.Parse(xvals[1]).CompareTo(Int32.Parse(yvals[1]));
            return cmp;
        }
    );
}

Comments

0

How about pre-padding your numbers with zeroes, so that they are fixed length. This way alphanumeric comparison will yield the same result as the numeric comparison you are expecting.

Comments

0

If you don't want to change your file names, you could do the padding during the comparison. I chose to pad it to ten numbers, but it may need to be more depending on how many files you have.

Array.Sort(fileEntries, (f1, f2) => f1.Name.PadLeft(10, '0').CompareTo(f2.Name.PadLeft(10, '0'));

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.