Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to sort out numeric strings as numerics?

If you have strings like:

"file_0"
"file_1"
"file_2"
"file_3"
"file_4"
"file_5"
"file_6"
"file_11"

how can you sort them so that "file_11" doesn't come after "file_1", but comes after "file_6", since 11 > 6.

Do I have to parse the string and convert it into a number for this?

Windows explorer in Win7 sorts files out the way I wanted.

like image 840
Joan Venge Avatar asked Aug 09 '09 08:08

Joan Venge


2 Answers

Do I have to parse the string and convert it into a number for this?

Essentially, yes; but LINQ may help:

var sorted = arr.OrderBy(s => int.Parse(s.Substring(5)));
foreach (string s in sorted) {
    Console.WriteLine(s);
}
like image 115
Marc Gravell Avatar answered Oct 20 '22 04:10

Marc Gravell


To handle sorting of intermixed strings and numbers for any kind of format, you can use a class like this to split the strings into string and number components and compare them:

public class StringNum : IComparable<StringNum> {

   private List<string> _strings;
   private List<int> _numbers;

   public StringNum(string value) {
      _strings = new List<string>();
      _numbers = new List<int>();
      int pos = 0;
      bool number = false;
      while (pos < value.Length) {
         int len = 0;
         while (pos + len < value.Length && Char.IsDigit(value[pos+len]) == number) {
            len++;
         }
         if (number) {
            _numbers.Add(int.Parse(value.Substring(pos, len)));
         } else {
            _strings.Add(value.Substring(pos, len));
         }
         pos += len;
         number = !number;
      }
   }

   public int CompareTo(StringNum other) {
      int index = 0;
      while (index < _strings.Count && index < other._strings.Count) {
         int result = _strings[index].CompareTo(other._strings[index]);
         if (result != 0) return result;
         if (index < _numbers.Count && index < other._numbers.Count) {
            result = _numbers[index].CompareTo(other._numbers[index]);
            if (result != 0) return result;
         } else {
            return index == _numbers.Count && index == other._numbers.Count ? 0 : index == _numbers.Count ? -1 : 1;
         }
         index++;
      }
      return index == _strings.Count && index == other._strings.Count ? 0 : index == _strings.Count ? -1 : 1;
   }

}

Example:

List<string> items = new List<string> {
  "item_66b",
  "999",
  "item_5",
  "14",
  "file_14",
  "26",
  "file_2",
  "item_66a",
  "9",
  "file_10",
  "item_1",
  "file_1"
};

items.Sort((a,b)=>new StringNum(a).CompareTo(new StringNum(b)));

foreach (string s in items) Console.WriteLine(s);

Output:

9
14
26
999
file_1
file_2
file_10
file_14
item_1
item_5
item_66a
item_66b
like image 31
Guffa Avatar answered Oct 20 '22 05:10

Guffa