# Properly ordering the output of FileNames for a directory consisting of files with consecutive integer names [duplicate]

Say I have a number of files in a directory at some location (C:\dir1\dir2\dir3...), and I pull an array of strings corresponding to the file names with the command:

fileList = FileNames["*", "C:\\dir1\\dir2\\dir3"]


Here, the files are named with consecutive integers (1 through N) and the output is automatically sorted like the following:

C:\dir1\dir2\dir3\10.tif
C:\dir1\dir2\dir3\11.tif
C:\dir1\dir2\dir3\12.tif
C:\dir1\dir2\dir3\13.tif
C:\dir1\dir2\dir3\14.tif
C:\dir1\dir2\dir3\15.tif
C:\dir1\dir2\dir3\16.tif
C:\dir1\dir2\dir3\17.tif
C:\dir1\dir2\dir3\18.tif
C:\dir1\dir2\dir3\19.tif
C:\dir1\dir2\dir3\1.tif
C:\dir1\dir2\dir3\20.tif
C:\dir1\dir2\dir3\2.tif
C:\dir1\dir2\dir3\3.tif
C:\dir1\dir2\dir3\4.tif
C:\dir1\dir2\dir3\5.tif
C:\dir1\dir2\dir3\6.tif
C:\dir1\dir2\dir3\7.tif
C:\dir1\dir2\dir3\8.tif
C:\dir1\dir2\dir3\9.tif


For any value N, is there an ordering function p I can apply to fileList (using Sort[fileList,p]) to arrange the entries in fileList to obey to proper integer ordering of the file names? Can I supply this ordering function directly to FileNames?

-

## marked as duplicate by István Zachar, Artes, Sjoerd C. de Vries, R. M.♦Sep 17 '13 at 23:45

You can do this in many ways. For example:

SortBy[filenames, ToExpression@FileBaseName[#] &]


Before @Leonid's comment I used StringDrop[FileNameTake[#], 4]& to get rid of ".tif". Now it is more general FileBaseName.

-
+1. I guess you could've used FileBaseName instead of StringDrop[...]. – Leonid Shifrin Sep 17 '13 at 10:54
@LeonidShifrin Yes, I knew there must be something built in. Thank you. :) – Kuba Sep 17 '13 at 10:56
But that's exactly what I meant with the ellipsis, othwerwise I'd just have mentioned StringDrop. – Leonid Shifrin Sep 17 '13 at 11:03
I am trying to be as precise in my comments as when coding (not that I do necessarily achieve it in either) :). Perhaps this was a bit cryptic. – Leonid Shifrin Sep 17 '13 at 11:07
@LeonidShifrin I should have known. But, there is a Slot included then :P Let's delete this conversation :) – Kuba Sep 17 '13 at 11:09

You can extract the numbers from each string using StringCases and ToExpression and sort according to those:

numbersInString[s_] := ToExpression@StringCases[s, NumberString]
SortBy[{"str2", "str10", "str1", "str11"}, numbersInString]
(* {"str1", "str2", "str10", "str11"} *)


However since this only extracts numbers it ignores all other characters in the strings.

Another way to do it is to pad all integers with 0's so they have the same length, and reorder the original list according to that:

StringPadLeft[s_String, n_, x_: " "] := StringJoin@PadLeft[Characters[s], n, x]

StringReplace[s, i : (DigitCharacter ..) :> StringPadLeft[i, n, "0"]]

integerAwareStringSort[l_List] := Module[{
max = Max[{1, ToExpression@StringCases[l, (DigitCharacter ..)]}]
},
]

integerAwareStringSort@{"a10", "b3", "a1", "b20", "3a40", "1a1", "1a50"}
(* {"1a1", "1a50", "3a40", "a1", "a10", "b3", "b20"} *)

-
I like the padding. About your first approach, we have to pay attention because OP does't say that dirNumber matters so it could have affect if we take: {"C:\\dir1\\dir3\\dir3\\4.tif", "C:\\dir1\\dir2\\dir3\\10.tif"} – Kuba Sep 17 '13 at 11:46

Let's suppose that you know that you won't have more than 1 000 000 different files, a nice trick is to name the i-th file as :

 "C:\\dir1\\dir2\\dir3\\"<>ToString[1000000+i]<>".tif"


Thanks to this, the lexicographic order of the file names works fine !

-