Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I sort strings alphabetically while accounting for value when a string is numeric?

I'm trying to sort an array of numbers that are strings and I'd like them to sort numerically.

The catch is that I cannot convert the numbers into int.

Here is the code:

string[] things= new string[] { "105", "101", "102", "103", "90" };  foreach (var thing in things.OrderBy(x => x)) {     Console.WriteLine(thing); } 

Output:

101, 102, 103, 105, 90 

I'd like:

90, 101, 102, 103, 105 

EDIT: The output can't be 090, 101, 102...

Updated the code sample to say "things" instead of "sizes". The array can be something like this:

string[] things= new string[] { "paul", "bob", "lauren", "007", "90" }; 

That means it needs to be sorted alphabetically and by number:

007, 90, bob, lauren, paul 
like image 990
sf. Avatar asked Jun 18 '11 13:06

sf.


People also ask

What is numeric sorting?

Numeric sort (' sort -n ') treats the entire string as a single numeric value, and compares it to other values. For example, ' 8.1 ', ' 8.10 ' and ' 8.100 ' are numerically equivalent, and are ordered together. Similarly, ' 8.49 ' is numerically less than ' 8.5 ', and appears before first.


1 Answers

Pass a custom comparer into OrderBy. Enumerable.OrderBy will let you specify any comparer you like.

This is one way to do that:

void Main() {     string[] things = new string[] { "paul", "bob", "lauren", "007", "90", "101"};      foreach (var thing in things.OrderBy(x => x, new SemiNumericComparer()))     {             Console.WriteLine(thing);     } }   public class SemiNumericComparer: IComparer<string> {     /// <summary>     /// Method to determine if a string is a number     /// </summary>     /// <param name="value">String to test</param>     /// <returns>True if numeric</returns>     public static bool IsNumeric(string value)     {         return int.TryParse(value, out _);     }      /// <inheritdoc />     public int Compare(string s1, string s2)     {         const int S1GreaterThanS2 = 1;         const int S2GreaterThanS1 = -1;          var IsNumeric1 = IsNumeric(s1);         var IsNumeric2 = IsNumeric(s2);          if (IsNumeric1 && IsNumeric2)         {             var i1 = Convert.ToInt32(s1);             var i2 = Convert.ToInt32(s2);              if (i1 > i2)             {                 return S1GreaterThanS2;             }              if (i1 < i2)             {                 return S2GreaterThanS1;             }              return 0;         }          if (IsNumeric1)         {             return S2GreaterThanS1;         }          if (IsNumeric2)         {             return S1GreaterThanS2;         }          return string.Compare(s1, s2, true, CultureInfo.InvariantCulture);     } } 
like image 178
Jeff Paulsen Avatar answered Sep 28 '22 06:09

Jeff Paulsen