Sort strings-digits

Possible duplicate:
Natural sort order in C #

I have a list with a lot of numbers. But they are saved as strings due to some extra letters.

My list looks something like this:

1 10 11 11a 11b 12 2 20 21a 21c A1 A2 ... 

but it should look like this:

 1 2 10 11a 11b ... A1 A2 ... 

How to sort the list to get this result?

+7
source share
4 answers

Following the previous comments, I would also implement the custom class IComparer<T> . From what I can assemble, the structure of the elements is either a number or a combination of a number followed by a letter (s). If so, the following implementation of IComparer<T> should be performed.

 public class CustomComparer : IComparer<string> { public int Compare(string x, string y) { var regex = new Regex("^(d+)"); // run the regex on both strings var xRegexResult = regex.Match(x); var yRegexResult = regex.Match(y); // check if they are both numbers if (xRegexResult.Success && yRegexResult.Success) { return int.Parse(xRegexResult.Groups[1].Value).CompareTo(int.Parse(yRegexResult.Groups[1].Value)); } // otherwise return as string comparison return x.CompareTo(y); } } 

With this IComparer<T> you can sort the string list by doing

 var myComparer = new CustomComparer(); myListOfStrings.Sort(myComparer); 

This has been tested with the following points:

2, 1, 4d, 4e, 4c, 4a, 4b, A1, 20, B2, A2, a3, 5, 6, 4f, 1a

and gives the result:

1, 1a, 2, 20, 4a, 4b, 4c, 4d, 4e, 4f, 5, 6, A1, A2, a3, B2

+12
source

Well, you need to extract a number from each line, and then sort the list of lines based on the list of numbers in the form of keys. Do this in two steps.

To extract a number from each line, the easiest way is to use a regular expression - look for a match for (\d+) (if you have negative or decimal numbers, you have to use another regular expression). Say you did this in a function called ExtractNumber

Now you can use some creative LINQ to sort, for example:

 strings.Select(s=>new { key=ExtractNumber(s), value=s }) // Create a key-value pair .OrderBy(p=>p.key) // Sort by key .Select(p=>p.Value); // Extract the values 
+2
source

Since this involves a lot of string operations, regular expression, etc., I don't think this is an efficient algorithm, but it seems to work.

 List<string> list1 = new List<string>() { "11c22", "1", "10", "11", "11a", "11b", "12", "2", "20", "21a", "21c", "A1", "A2" }; List<string> list2 = new List<string>() { "File (5).txt", "File (1).txt", "File (10).txt", "File (100).txt", "File (2).txt" }; var sortedList1 = NaturalSort(list1).ToArray(); var sortedList2 = NaturalSort(list2).ToArray(); 

 public static IEnumerable<string> NaturalSort(IEnumerable<string> list) { int maxLen = list.Select(s => s.Length).Max(); Func<string, char> PaddingChar = s => char.IsDigit(s[0]) ? ' ' : char.MaxValue; return list .Select(s => new { OrgStr = s, SortStr = Regex.Replace(s, @"(\d+)|(\D+)", m => m.Value.PadLeft(maxLen, PaddingChar(m.Value))) }) .OrderBy(x => x.SortStr) .Select(x => x.OrgStr); } 
+1
source

I am new to C #, but here is the solution I appreciate in Java: you need to go through 2 steps, first define a custom IComparer, and then use it when calling the sort method. Therefore, you should be able to do something like:

 public class MyListSorter : IComparer<MyObject> { public int Compare(MyObject obj1, MyObject obj2) { if ( !Char.IsNumber(obj1) && Char.IsNumber(obj2) ) { return 0; } else if ( Char.IsNumber(obj1) && !Char.IsNumber(obj2) ) { return 1; } else { return obj2.CompareTo(obj1); } } } 

and then

 myObjectList.Sort(new MyListSorter()); 

Additional information about IComparer: http://support.microsoft.com/kb/320727

0
source

All Articles