Sahil Sahil - 1 month ago 7
C# Question

sorting when name includes letters and numeric digits

I have following array

[0] = GB_22_T0001.jpg
[1] = GB_22_T0002.jpg
[2] = GB_22_T0003.jpg
[3] = GB_22_T0006.jpg
[4] = GB_22_T0007.jpg
[5] = GB_22_T0008.jpg
[6] = GB_22_T0009.jpg
[7] = GB_22_T00010.jpg
[8] = GB_22_T00011.jpg
[9] = GB_22_T00012.jpg
[10] = GB_22_T00013.jpg


I have put this items in a listbox and noticed that 'GB_22_T00010' comes straight after 'GB_22_T0001' instead of 'GB_22_T0002'

Seems to be a common issue with c# but cannot find a common answer to the problem.

I tried sorting the array with Array.sort(data) and also tried LinQ's OrderBy method but none of them helps.

Anyone with a solution?

Answer

GB_22_T0001 is a string not a number. So it's sorted lexicographically instead of numerically. So you need to parse a part of the string to an int.

var ordered = array.Select(Str => new { Str, Parts=Str.Split('_') })
                   .OrderBy(x => int.Parse(x.Parts.Last().Substring(1))) 
                   .Select(x => x.Str);

Split('_') splits the string into substrings on a delimiter _. The last substring contains your numeric value. Then i use String.Substring to take only the numeric part(remove the starting T) for int.Parse. This integer is used for Enumerable.OrderBy. The last step is to select just the string instead of the anonymous type.

Edit: Here is the version that supports Paths:

var ordered = array.Select(str => { 
    string fileName = Path.GetFileNameWithoutExtension(str);
    string[] parts =  fileName.Split('_');
    int number = int.Parse(parts.Last().Substring(1));
    return new{ str, fileName, parts, number };
 })
.OrderBy(x => x.number)
.Select(x => x.str);