16

I have a List like this:

var l = new List<string> {"bla 1.txt","bla 2.txt","bla 10.txt","bla 3.txt"};

If i call l.Sort(), the list gets sorted in the order 1,10,2,3 which makes sense from a pure string point of view, but sucks from a User Perspective.

Since I don't want to/can't force my users to name them 01, 02, 03,... I wonder if there is either a built-in method or simple algorithm to detect and sort numbers properly, so that I have 1,2,3,10? Since the numbers are only 1 or 2 characters long (i.e., no more than 99) I could possibly do a regex that temporarily prefixes all 1-digit numbers with a 0 and sort, but before I reinvent the wheel I wonder if something already exists?

.net 3.5SP1 if that matters, not 4.0

Michael Stum
  • 177,530
  • 117
  • 400
  • 535

3 Answers3

20

The best approach is making use of IComparer. This has already been done and can be found on code project.

Aaron McIver
  • 24,527
  • 5
  • 59
  • 88
  • I've used this same solution in the past - worked like a charm! – Mark Carpenter Jan 24 '11 at 23:14
  • 1
    I like existing and tested solutions - works like a charm! Hint for anyone who wants to use this: Get rid of NumericComparer.cs, move the Compare function to StringLogicalComparer, make the Compare(string,string) non-static and have the class implement IComparer, IComparer – Michael Stum Jan 24 '11 at 23:22
  • This is a sort of "Link only answer". That code isn't reachable without a login and could change\disappear. It would be helpful to reduce it to a small class that would fit in a post here. – HackSlash Jun 22 '18 at 19:58
  • The "existing solution" is `shlwapi.dll` StrCmpLogicalW – HackSlash Jun 22 '18 at 20:23
11

Why not write something that will extract a number from a string, like this?

// Note: This could very well be a bad implementation. I'm not too great with Regex.
static int ExtractNumber(string text)
{
    Match match = Regex.Match(text, @"(\d+)");
    if (match == null)
    {
        return 0;
    }

    int value;
    if (!int.TryParse(match.Value, out value))
    {
        return 0;
    }

    return value;
}

Then you could sort your list using:

list.Sort((x, y) => ExtractNumber(x).CompareTo(ExtractNumber(y)));

This strikes me as pretty inefficient, but it should be functional at least.

Dan Tao
  • 125,917
  • 54
  • 300
  • 447
0

You could implement your own IComparer that maybe uses a regular expression on the input ("bla 1.txt"), converts that to an int, and peforms the comparison on that parsed value.

Babak Naffas
  • 12,395
  • 3
  • 34
  • 49