Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to sort a string array by numeric style?

I have a filenames array, I want to sort it by numeric style, please give to me a solution.

Example1:

Original array: [name99.txt, name98.txt, name100.txt]
Sorted array: [name98.txt, name99.txt, name100.txt]
(Using string sorting, result of sorting is [name100.txt, name98.txt, name99.txt])

Example2:

Original array: [a99.txt, b98.txt, b100.txt]
Sorted array: [a99.txt, b98.txt, b100.txt]
(Using string sorting, result of sorting is [a99.txt, b100.txt, b99.txt])

like image 608
hungbm06 Avatar asked Jul 17 '11 11:07

hungbm06


2 Answers

string[] ar = new string[] { "name99.txt", "name98.txt", "name100.txt" };
Array.Sort(ar, (a, b) => int.Parse(Regex.Replace(a, "[^0-9]", "")) - int.Parse(Regex.Replace(b, "[^0-9]", "")));

foreach (var a in ar)
    Console.WriteLine(a);

The above assumed that your files are allways called name###.txt. For the real numeric sorting use the following more complicated version:

public static void NumericalSort(string[] ar)
{
    Regex rgx = new Regex("([^0-9]*)([0-9]+)");
    Array.Sort(ar, (a, b) =>
    {
        var ma = rgx.Matches(a);
        var mb = rgx.Matches(b);
        for (int i = 0; i < ma.Count; ++i)
        {
            int ret = ma[i].Groups[1].Value.CompareTo(mb[i].Groups[1].Value);
            if (ret != 0)
                return ret;

            ret = int.Parse(ma[i].Groups[2].Value) - int.Parse(mb[i].Groups[2].Value);
            if (ret != 0)
                return ret;
        }

        return 0;
    });
}

static void Main(string[] args)
{
    string[] ar = new string[] { "a99.txt", "b98.txt", "b100.txt" };

    NumericalSort(ar);

    foreach (var a in ar)
        Console.WriteLine(a);
}
like image 85
Petar Ivanov Avatar answered Oct 23 '22 22:10

Petar Ivanov


There may well be a managed way to do this, but I would probably just P/invoke to StrCmpLogicalW.

[DllImport("shlwapi.dll", CharSet=CharSet.Unicode, ExactSpelling=true)]
static extern int StrCmpLogicalW(String x, String y);    

If you use this function, rather than rolling your own comparison function, you'll get the same behaviour as Explorer and other system components that use logical comparison.

Note, however, that this will not work in environments where WinAPI is inaccessible (such as Windows Phone, Mono or Silverlight), might work differently on different systems and should be decorated with a comment so the future maintainer of your code knows why P/Invoke is used for sorting.

like image 45
David Heffernan Avatar answered Oct 23 '22 22:10

David Heffernan