Share via


Default Sorting of the characters in c#

Question

Tuesday, April 8, 2014 3:18 PM

Hi All,

I will be highly obliged if you could solve my issue. 

The issue which I am facing that is about the sorting order of the Special Chars, Numbers and Alphbets.

I think default sorting is Special Chars -> Numbers -> Alphbets in Ascending order. Suppose I have below data 

"Test1","12234","23","@abc","@123"

if we sort the above data in c# in ascending order then we will get the following result

"@123","@abc","12234","23","test1"

But as per my requirement , I want the sorting to be Numbers -> Special Chars ->Alphabets

The above result should come as 

"12234","23","@123","@abc","test1"

And these results I am displaying in the DataGrid, So I want to change the way of default sorting of the grid so that the above result can be achieved.

Thanks in advance.

All replies (3)

Tuesday, April 8, 2014 4:07 PM âś…Answered

There are overloads to List<>.Sort() that accepts custom comparers.

You can also substitue a lambda for an IComparer. This is handy for cases like this where you want a one-off sort. If this isn't a one-off, you're probably better off with a custom IComparer class. Here's how you'd do this brute force style:

List<string> list = new List<string>() { "Test1", "12234", "23", "@abc", "@123" };

list.Sort((x, y) =>
{
    if (!Char.IsLetterOrDigit(x[0]))
    {
        if (Char.IsLetter(y[0]))
            return -1;
        else if (Char.IsDigit(y[0]))
            return 1;
    } 
    return x.CompareTo(y);
});

foreach (var s in list)
   Console.WriteLine(s);

output

12234
23
@123
@abc
Test1

Hope this helps.


Tuesday, April 8, 2014 4:04 PM

But as per my requirement , I want the sorting to be Numbers -> Special Chars ->Alphabets

You can use Linq to perform custom sorting based on  your requirement. This could be optimized or modified. But, here is an initial example to begin with

using System.Linq;
using System.Collections.Generic;
var input = new string[] { "12234", "23", "@123", "@abc", "test1" };
var output = new List<string>();
int value = 0;
//order numbers
output.AddRange(input.Where(a => int.TryParse(a, out value)).OrderBy(a => int.Parse(a)).ToList());
//order special characters 
output.AddRange(input.Where(a => !char.IsLetterOrDigit(a[0])).OrderBy(a => a));
//order string 
output.AddRange(input.Where(a => char.IsLetter(a[0])).OrderBy(a => a));


Tuesday, April 8, 2014 4:25 PM

You can write your own custom comparer:

    public class CustomComparer : IComparer<string>
    {
        public int Compare(string x, string y)
        {
            int compare = 0;
            if (Char.IsNumber(x[0]) && (Char.IsLetter(y[0])|| !Char.IsLetterOrDigit(y[0])))
                compare = -1;

            if (Char.IsLetter(x[0]) && (Char.IsNumber(y[0]) || !Char.IsLetterOrDigit(y[0])))
               compare = 1;
            if (!Char.IsLetterOrDigit(x[0]) && Char.IsLetter(y[0]))
                compare = -1;
            if (!Char.IsLetterOrDigit(x[0]) && Char.IsNumber(y[0]))
                compare = 1;

            return compare;
        }
    }

Then you can pass that in to the the OrderBy method:

var input = new[] { "Test1", "12234", "23", "@abc", "@123" };
foreach (var i in input.OrderBy(s => s, new CustomComparer()))
{
    Console.WriteLine(i);
}

[EDIT]

There's a bug in my algorithm. If you want a custom comparer class, replace the body of my Compare method with Smirnov's (correct) implementation.