Link to home
Start Free TrialLog in
Avatar of wint100
wint100Flag for United Kingdom of Great Britain and Northern Ireland

asked on

Sort a List<String> in numeric order in silverlight

I have a List<String> in a SL4 app that I invoke the sort() method, so sort the items in order. This works great on alphnumeric characters, but I need to store the strings as numeric values.

If I have a List<String> with strings "1", "2", "10", the sort will sort as

1
10
2

I need to sort this in numeric order, can anyone help out with this in Silverlight.

Thanks
Avatar of Todd Gerbert
Todd Gerbert
Flag of United States of America image

Why not a List<int> instead?
Avatar of wint100

ASKER

The list actually holds a list of filenames (ie 1.jpg), so it has to stay as string as the name could be anything.
I figured something like that would probably be the case, but when I make an assumption I usually end up dead-wrong, so I thought I'd better ask. ;)

Are the filenames always some numeric characters followed by a dot and an extension?  That is, you don't ever have filenames without numbers in the list - or filenames like 123_SomeOtherText.jpg - do you?
Avatar of wint100

ASKER

No the name can be anything, it just so happens this particular case has a list of files named with only a number, which made me notice the issue with sorting.
Are you just concerned about file names that start with a number? I've got  an idea for the case where numbers appear in the middle of a string, but more than one group of numbers separated by letters might get a little  tricky.
Avatar of wint100

ASKER

How would that work if the files were:

File1.jpg
File2.jpg
File10.jpg

The files should be un the order above but I think the File10.jpg would be put second.
This examples uses the first number found in the filename to do the comparisons.  A filename with a number will always come before a filename with NO number.  If neither filename has a number in it then a straight string comparison is used.

Add "using System.Text.RegularExpressions;" to the top of your code:

private void Foo()
        {
            string[] FileNames = System.IO.Directory.GetFiles(@"C:\Users\Mike\Pictures\Wallpaper", "*.jpg");
            Array.Sort(FileNames, NumericFileSorter);
            foreach (string FileName in FileNames)
                Console.WriteLine(FileName);
        }

        private int NumericFileSorter(string File1, string File2)
        {
            int result = 0;
            int Num1, Num2;
            Match Match1, Match2;
            Match1 = Regex.Match(File1, @"\d+");
            Match2 = Regex.Match(File2, @"\d+");
            if (Match1.Success)
            {
                if (Match2.Success)
                {
                    // both File1 and File2 had a number...convert them to ints
                    if (int.TryParse(Match1.ToString(), out Num1) && int.TryParse(Match2.ToString(), out Num2))
                    {
                        // numbers successfully converted to ints...do the NUMERIC comparison
                        result = Num1.CompareTo(Num2);
                    }
                    else
                    {
                        // something went wrong with the parse...default to string comparison
                        result = File1.CompareTo(File2);
                    }
                }
                else
                {
                    // File1 had a number but File2 did not
                    result = -1;
                }
            }
            else
            {
                if (Match2.Success)
                {
                    // File2 had a number but File1 did not
                    result = 1;
                }
                else
                {
                    // neither File1 or File2 had a number...just do a string comparison
                    result = File1.CompareTo(File2);
                }
            }
            return result;
        }

Open in new window

*The example was for C# WinForms and an Array.  It would be very similar for a List<string>...just use YourListName.Sort(NumericFileSorter).  Hopefully you'll know how to use it in a Silverlight app.
My idea is similar, using a custom sorting function...but using Regex to pull numeric digits, parse them into an Int32, then put it back into the string with leading zero's for the sake of comparison.  That way File1.jpg, File2.jpg and File10.jpg would (just for the sake of sorting, without changing the original strings) sort as File00000001.jpg, File00000002.jpg and File00000010.jpg.

Usage:
List<string> files = new List<string>(new string[] { "NoNumbers.jpg", "File1.jpg", "File3.jpg", "File10.jpg", "File2.jpg" });
NumericStringListSorter.Sort(files);

Open in new window


The NumericStringListSorter:
public class NumericStringListSorter
{
	private static Regex regex = new Regex(@"\d{1,7}");

	public static void Sort(List<string> list)
	{
		list.Sort(delegate(string x, string y)
		{
			if (x == null && y == null)
				return 0;
			else if (x == null && y != null)
				return -1;
			else if (x != null && y == null)
				return 1;
			else
			{
				x = regex.Replace(x, (Match m) => Int32.Parse(m.Value).ToString("D8"));
				y = regex.Replace(y, (Match m) => Int32.Parse(m.Value).ToString("D8"));

				return x.CompareTo(y);
			}
		});
	}
}

Open in new window

Of course, that example assumes there won't be any number groups larger than 9999999, but you could adjust the regex and possibly use a data type larger than Int32, with some overflow-checking.
ASKER CERTIFIED SOLUTION
Avatar of Todd Gerbert
Todd Gerbert
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of wint100

ASKER

The last post looks good, I'm just testing now. I found the following article, but doubt it can be applied easily to Silverlight, what do you think:

http://www.codeproject.com/KB/recipes/csnsort.aspx
The code in that article will probably run in Silverlight without change, but it looks awfully convoluted.