Reputation: 3285
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));
}
Upvotes: 1
Views: 4702
Reputation: 18155
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;
}
);
}
Upvotes: 1
Reputation: 60556
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…?
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());
Upvotes: 4
Reputation: 12261
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();
Upvotes: 3
Reputation: 4854
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'));
Upvotes: 0
Reputation: 7545
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)
Upvotes: 1
Reputation: 120518
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.
Upvotes: 0