1

I have an array of strings like the following:

"access"
"Addition"
"account"
"base"
"Brick"
"zammer"
"Zilon"

I want them to sort them witht the following rules"

  1. Capital letters for a given character should come first.
  2. The capital and small letters should be sorted in their own groups.

Thus, the output should be:

"Addition"
"access"
"account"
"Brick"
"base"
"Zilon"
"zammer"

The language I am using is C# and .Net 4.0.

Vignesh Kumar A
  • 27,863
  • 13
  • 63
  • 115
James
  • 1,213
  • 2
  • 15
  • 26

4 Answers4

7

Proper set of OrderBy/ThenBy calls will do the trick.

  1. Order by first letter lowercased, to get all as and As first, then bs and Bs, etc.
  2. Then by IsLower(firstCharacter), which will get the uppercased items for each letter first.
  3. Then by the entire string.
var sorted = source.OrderBy(s => char.ToLower(s[0]))
                   .ThenBy(s => char.IsLower(s[0]))
                   .ThenBy(s => s)
                   .ToList();
MarcinJuraszek
  • 124,003
  • 15
  • 196
  • 263
0

Try like this

List<string> list = new List<string>();
list.Add("access");
list.Add("Addition");
list.Add("account");
list.Add("base")
list.Add("Brick")
list.Add("zammer")
list.Add("Zilon")
list = list.Where(r => char.IsLower(r[0])).OrderBy(r => r)
      .Concat(list.Where(r => char.IsUpper(r[0])).OrderBy(r => r)).ToList();
for (int i = 0; i < list.Count; i++)
    Console.WriteLine(list[i]);
Vignesh Kumar A
  • 27,863
  • 13
  • 63
  • 115
0

Below solution works for more than one Caps.

   static void Main(string[] args)
    {

        var names = new List<String>() {
        "access",
        "Addition",
        "ADDition",
        "ADdition",
        "account",
         "base",
        "Brick",
        "zammer",
        "Zilon"
        };


        names.Sort((one, two) =>
        {
            int result = 0;

            var oneArray = one.ToCharArray();
            var twoArray = two.ToCharArray();

            var minLength = Math.Min(oneArray.Length, twoArray.Length) - 1;
            var i = 0;

            while (i < minLength)
            {
                //Diff Letter
                if (Char.ToUpper(one[i]) != Char.ToUpper(two[i]))
                {
                    result = Char.ToUpper(one[i]) - Char.ToUpper(two[i]);
                    break;
                }

                // Same Letter, same case
                if (oneArray[i] == twoArray[i])
                {
                    i++;
                    continue;
                }
                // Same Letter, diff case
                result =  one[i] - two[i];
                break;
            }

            return result;
        });

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

        Console.WriteLine("done");
Avi
  • 1
  • 2
0

If you want to go beyond the first character, I should implement a comparer:

class MyComparer : IComparer<string>
{
    public int Compare(string x, string y)
    {
        if ((x == null) && (y == null))
        {
            return 0;
        }

        if (x == null)
        {
            return 1;
        }

        if (y == null)
        {
            return -1;
        }

        var l = Math.Min(x.Length, y.Length);
        for (var i = 0; i < l; i++)
        {
            var c = x[i];
            var d = y[i];
            if (c != d)
            {
                if (char.ToLowerInvariant(c) == char.ToLowerInvariant(d))
                {
                    return StringComparer.Ordinal.Compare(new string(c, 1), new string(d, 1));
                }
                else
                {
                    return StringComparer.OrdinalIgnoreCase.Compare(new string(c, 1), new string(d, 1));
                }
            }
        }

        return x.Length == y.Length ? 0 : x.Length > y.Length ? 1 : -1;
    }
}

And then use it:

var myComparer = new MyComparer();
source.OrderBy(s => s, myComparer);
Paulo Morgado
  • 14,111
  • 3
  • 31
  • 59