0

We have a problem about sorting strings. Sort doesnt work in such case

1-A 1-B 10-A 10-B 9-A 9-B ...

What we really want is

1-A 1-B 9-A 9-B 10-A 10-B If we sort it as string the result would be like in the first part. If we parse then sort then how can we sort the rest of A's and B's? Is there any simple solution for c#?

Thanks;

albatross
  • 455
  • 2
  • 8
  • 27
  • Very similar problem (soring file names like "foo123.txt") is covered in [C# Natural sort order](http://stackoverflow.com/questions/248603/natural-sort-order-in-c-sharp) question. You can find more using "C# natural sort" as search terms on you favorite search engine. – Alexei Levenkov May 26 '14 at 07:57

7 Answers7

2

You may implement own comparer where you put your custom comparison logic. Then you may use this comparer instance for performing sorting.

st4hoo
  • 2,196
  • 17
  • 25
1

I would suggest to use the IComparer

It is easy to implement and sorts in the way you were after, Example.

1.txt
10.txt
3.txt
a10b1.txt
a1b1.txt
a2b1.txt
a2b11.txt
a2b2.txt
b1.txt
b10.txt
b2.txt  

Sorted to

1.txt
3.txt
10.txt
a1b1.txt
a2b1.txt
a2b2.txt
a2b11.txt
a10b1.txt
b1.txt
b2.txt
b10.txt
Karl-Henrik
  • 1,113
  • 1
  • 11
  • 17
1

just use the following code

string[] strArr = new string[] {"1-A", "1-B", "9-A", "9-B", "10-A", "10-B"};
var q = from t in strArr select new { FirstPart =Convert.ToInt32(t.Split('-')[0]), SecondPart = t.Split('-')[1] };

string[] resArr = q.OrderBy(p => p.FirstPart).ThenBy(p => p.SecondPart).Select(p=> string.Concat(p.FirstPart, "-", p.SecondPart)) .ToArray();
Mohamed
  • 470
  • 3
  • 14
1

One way, you can use LINQ's OrderBy+ThenBy:

string[] strings = {"1-A", "1-B", "10-A", "10-B", "9-A", "9-B"}; 
int i = 0;
var orderedStrings = strings
   .Select(str => new { arr = str.Split('-'), str })
   .Where(x => x.arr.Length == 2 && int.TryParse(x.arr[0], out i))
   .Select(x => new { x.str, x.arr, num = int.Parse(x.arr[0])})
   .OrderBy(x => x.num)
   .ThenBy(x => x.arr[1])
   .Select(x => x.str); 

Presumes that the string is always separated by -, contains two parts and the first is always an int. This is ensured with Where, strings which have an invalid format are omitted.

If you want to reassign the ordered query to your string[], you need to create a new one:

strings = orderedStrings.ToArray();
Tim Schmelter
  • 450,073
  • 74
  • 686
  • 939
1

You are looking for a "natural sort order".

It turns out that the Windows API provides a StrCmpLogicalW() function that we can call using P/Invoke to solve the issue.

Assuming that you are trying to sort a List<> or an array, you can wrap it in an extension method to make it easier to call:

public static class ListAndArrayExt
{
    [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
    private static extern int StrCmpLogicalW(string lhs, string rhs);

    public static void SortNatural(this List<string> self)
    {
        self.Sort(StrCmpLogicalW);
    }

    public static void SortNatural(this string[] self)
    {
        Array.Sort(self, StrCmpLogicalW);
    }
}

You can then use it to sort a List<> in natural sort order. Here's a complete compilable Console app to demonstrate:

using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;

namespace ConsoleApp1
{
    public static class ListAndArrayExt
    {
        [DllImport("shlwapi.dll", CharSet = CharSet.Unicode)]
        private static extern int StrCmpLogicalW(string lhs, string rhs);

        public static void SortNatural(this List<string> self)
        {
            self.Sort(StrCmpLogicalW);
        }

        public static void SortNatural(this string[] self)
        {
            Array.Sort(self, StrCmpLogicalW);
        }
    }

    class Program
    {
        void run()
        {
            var strings = new List<string>
            {
                "1-A",
                "1-B",
                "10-A",
                "10-B",
                "9-A",
                "9-B"
            };

            strings.SortNatural();

            foreach (var s in strings)
                Console.WriteLine(s);
        }

        static void Main()
        {
            new Program().run();
        }
    }
}

This prints out the strings like so:

1-A
1-B
9-A
9-B
10-A
10-B
Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
0

You need to implement custom comparer which will compere string as you like. e.g. NaturalComparer

Vladimir Sachek
  • 1,126
  • 1
  • 7
  • 20
-2

try to use

ArrayList

then use

ArrayList.Sort();

it will sort your array.

Haitham242
  • 27
  • 7