Solved

Sort a List<String> in numeric order in silverlight

Posted on 2011-02-15
13
833 Views
Last Modified: 2012-05-11
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
0
Comment
Question by:wint100
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 7
  • 4
  • 2
13 Comments
 
LVL 33

Expert Comment

by:Todd Gerbert
ID: 34900304
Why not a List<int> instead?
0
 
LVL 1

Author Comment

by:wint100
ID: 34900333
The list actually holds a list of filenames (ie 1.jpg), so it has to stay as string as the name could be anything.
0
 
LVL 33

Expert Comment

by:Todd Gerbert
ID: 34900534
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?
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 1

Author Comment

by:wint100
ID: 34900573
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.
0
 
LVL 33

Expert Comment

by:Todd Gerbert
ID: 34900676
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.
0
 
LVL 1

Author Comment

by:wint100
ID: 34900763
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.
0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 34901399
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

0
 
LVL 86

Expert Comment

by:Mike Tomlinson
ID: 34901451
*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.
0
 
LVL 33

Expert Comment

by:Todd Gerbert
ID: 34901782
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

0
 
LVL 33

Expert Comment

by:Todd Gerbert
ID: 34901870
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.
0
 
LVL 33

Accepted Solution

by:
Todd Gerbert earned 500 total points
ID: 34901958
I guess that could be shortened up a bit...

public static void Sort(List<string> list)
{
	list.Sort(delegate(string x, string y)
	{
		if (x == null || y == null)
			return String.Compare(x, y);
		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

0
 
LVL 1

Author Comment

by:wint100
ID: 34904504
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
0
 
LVL 33

Expert Comment

by:Todd Gerbert
ID: 34906250
The code in that article will probably run in Silverlight without change, but it looks awfully convoluted.
0

Featured Post

How Do You Stack Up Against Your Peers?

With today’s modern enterprise so dependent on digital infrastructures, the impact of major incidents has increased dramatically. Grab the report now to gain insight into how your organization ranks against your peers and learn best-in-class strategies to resolve incidents.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

We all know that functional code is the leg that any good program stands on when it comes right down to it, however, if your program lacks a good user interface your product may not have the appeal needed to keep your customers happy. This issue can…
Introduction Hi all and welcome to my first article on Experts Exchange. A while ago, someone asked me if i could do some tutorials on object oriented programming. I decided to do them on C#. Now you may ask me, why's that? Well, one of the re…
Finds all prime numbers in a range requested and places them in a public primes() array. I've demostrated a template size of 30 (2 * 3 * 5) but larger templates can be built such 210  (2 * 3 * 5 * 7) or 2310  (2 * 3 * 5 * 7 * 11). The larger templa…

730 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question