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.

4 Answers 4

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();
Sign up to request clarification or add additional context in comments.

7 Comments

It might be nicer to be: source.OrderBy(s => char.ToLower(s[0])).ThenByDescending(s => s). That seems to do the job. +1 anyway.
+1, but won't that only work if there are no caps in the middle of the string? (granted, there aren't any in the OP's example but the stated requirements don't preclude this possibility).
@Baldrick Yes, I assumed the upper/lower rule works only for first character.
@MarcinJuraszek: Hmm.. would be nice to get a more general solution.. but probably just perfect for OP's problem! Nice work.
The strings can very well contain caps in between.
|
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]);

Comments

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");

Comments

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);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.