0

I am trying to re-order strings in an array, based on if they match a string value.

My program is getting a list of files in a directory, and then renaming and moving the files. But I need certain files with a specific name to be renamed after other files. (the files are being renamed with time stamps and are processed in that order).

Example File names:

File-302.txt
File-302-IAT.txt
File-303.txt
File-303-IAT.txt
File-304.txt
File-304-IAT.txt
File-305.txt
File-305-IAT.txt

Basically what I am trying to accomplish, is I would like to move all the files containing "-IAT" to the end if the array, so that when I loop through, the IAT files are processed after their non "IAT" partner file.

Here is my code but theres not much to it:

string[] outFiles = Directory.GetFiles(workingDir);

for (int i = 0; i <= outFiles.Length - 1; i++
{
    //code to rename the file in the array
}
5
  • have you executed a simple google search on how to order a string array for example type this in the google search C# stackoverflow how to order an array of strings Commented May 25, 2017 at 16:07
  • 2
    You can put those files after the others with outFiles.Where(f => !f.Contains("-IAT")).Concat(outFiles.Where(f => f.Contains("-IAT")) but apart from that you haven't said what order you want the results in - you mention they are processed in order of timestamp? Commented May 25, 2017 at 16:10
  • @stuartd that should be an answer in my opinion. I was going to add that myself but you beated me Commented May 25, 2017 at 16:17
  • @MethodMan, roger, however I just didn't see an example that quite suited what I needed, most of what I could find just was some prebuilt .net code on sorting alphabetically, which is not necessarily what I need. Also im still somwhat of a noob -obviously. Commented May 25, 2017 at 16:25
  • @stuartd - Thanks. Honestly the order itself isn't really that important, as long as the IAT file is processed after the respective non IAT file. That's why I figured it would be easier just to shove all of them at the end, regardless of the name. Commented May 25, 2017 at 16:26

3 Answers 3

4

You can use a custom IComparer<string> implementing your sorting rule:

class IatEqualityComparer : IComparer<string>
{
    public int Compare(string a, string b)
    {
        if (a == b)
            return 0;
        var aWithoutExtension = Path.GetFileNameWithoutExtension(a);
        var bWithoutExtension = Path.GetFileNameWithoutExtension(b);
        var aIsIat = aWithoutExtension.EndsWith("IAT", StringComparison.InvariantCultureIgnoreCase);
        var bIsIat = bWithoutExtension.EndsWith("IAT", StringComparison.InvariantCultureIgnoreCase);
        if (aIsIat && !bIsIat)
            return 1;
        if (!aIsIat && bIsIat)
            return -1;
        return a.CompareTo(b);
    }
}

(In Windows file names are not case sensitive so you have to be very careful when you look for a specific pattern like IAT in a file name. It will almost always work as expected except for that one time in production where the file ended with iat and not IAT...)

You can then sort an array using Array.Sort:

Array.Sort(outFiles, new IatEqualityComparer());

This will sort the array in place. The result is:

File-302.txt
File-303.txt
File-304.txt
File-305.txt
File-302-IAT.txt
File-303-IAT.txt
File-304-IAT.txt
File-305-IAT.txt

The IComparer<string> can also be used when sorting lists in place and with LINQ OrderBy.

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

1 Comment

Thank you, I think this is exactly what I needed.
1

If you project your items into a new sequence with two different ordering fields, you can then use LINQ to sort the projection accordingly, then extract the file name from the resulting sequence:

outFiles
    .Select(fn => new{
        order = Path.GetFileNameWithoutExtension(fn).EndsWith("-IAT") ? 1 : 0,
        fn
    })
    .OrderBy(x => x.order)
    .ThenBy(x => x.fn)
    .Select(x => x.fn)

Comments

0

Actually, what I ended up doing was just a simple bubble sort, as the amount of files i am dealing with is very small. I changed from storing the files in an array to a list.

List<string> outFiles = new List<string>(Directory.GetFiles(workingDir));
bool noSort;

do
{
    noSort = true;
    for (int i = 0; i <= outFiles.Count - 2; i++)
    {
        if (outFiles[i].EndsWith("IAT.TXT"))
        {
            if (!outFiles[i + 1].EndsWith("IAT.TXT"))
            {
                string temp = outFiles[i + 1];
                outFiles[i + 1] = outFiles[i];
                outFiles[i] = temp;
                noSort = false;
            }
        }
    }
}
while (noSort == false);

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.