-2

I have values in a string list like

AB1001_A
AB1001_B
AB1002_2
AB1002_C
AB1003_0
AB1003_
AB1003_B
AB1003_A
AB1001_0
AB1001_1
AB1001_2
AB1001_C
AB1002_B
AB1002_A

And I wanted to sort this by ascending order and the suffixes in descending order like below

AB1001_2
AB1001_1
AB1001_0
AB1001_C
AB1001_B
AB1001_A
AB1002_0
AB1002_B
AB1002_A
AB1003_0
AB1003_B
AB1003_A
AB1003_

How can I code it in C#.net?

TheGeneral
  • 79,002
  • 9
  • 103
  • 141
  • So, what have you researched, what is not working? – TheGeneral Oct 13 '20 at 07:31
  • I tried PadNumbers using regex. But I coudn't sort the suffix only in descending format and the remaining in ascending format – Saran Mohan Oct 13 '20 at 07:34
  • 1
    Does this answer your question? [How can I order a List?](https://stackoverflow.com/questions/10211470/how-can-i-order-a-liststring) – funie200 Oct 13 '20 at 07:34
  • 1
    The suffixes in your expected results are not sorted in descending order, because if they were they would be "C", "B", "A", "2", "1", "0" (numbers come before letters in alphabetical order). – Matthew Watson Oct 13 '20 at 07:40
  • See [OrderBy](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.orderby) and [ThenBy](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.thenby). But you will need your own comparer to sort the suffixes in the order you want – Hans Kesting Oct 13 '20 at 07:51
  • How long can the suffixes be? Are they limited to a single character? If not, can they mix letters and digits? – Matthew Watson Oct 13 '20 at 07:53
  • Also, can you explain why you have `AB1002_2` in the input but not in the expected output? – Matthew Watson Oct 13 '20 at 08:03
  • suffix always will be single character with "_". But it can be either Alphabet or number. But number should come first then alphabet in descending order – Saran Mohan Oct 13 '20 at 09:57

3 Answers3

1

It is quite strange sorting, but if you really need it, try something like this:

List<string> lItemsOfYourValues = new List<string>() {"AB1001_A","AB1001_B","AB1001_0" /*and next your values*/};

List<Tuple<string,string,string>> lItemsOfYourProcessedValues = new List<Tuple<string,string,string>>();
string[] arrSplitedValue;

for(int i = 0; i < lItemsOfYourValues.Count; i++) 
{

arrSplitedValue = lItemsOfYourValues[i].Split("_");

lItemsOfYourProcessedValues.add(new Tuple<string,string,string>(lItemsOfYourValues[i], arrSplitedValue[0], arrSplitedValue[1]));

}

List<string> lSortedValues = lItemsOfYourProcessedValues.OrderBy(o => o.Item2).ThenByDescending(o => o.Item3).Select(o => o.Item1).ToList();
Martin Zaloga
  • 127
  • 1
  • 10
0

It looks like you have an error in your expected results, since AB1002_2 is in the input but not in the expected results.

Assuming that's just an error, and further assuming that the suffixes are limited to a single character or digit, you can solve the sorting by writing a special comparer like so:

static int compare(string x, string y)
{
    var xParts = x.Split('_', StringSplitOptions.RemoveEmptyEntries);
    var yParts = y.Split('_', StringSplitOptions.RemoveEmptyEntries);

    if (xParts.Length != yParts.Length)
        return yParts.Length - xParts.Length; // No suffix goes after suffix.

    if (xParts.Length == 0) // Should never happen.
        return 0;

    int comp = string.Compare(xParts[0], yParts[0], StringComparison.Ordinal);

    if (comp != 0 || xParts.Length == 1)
        return comp;

    if (char.IsDigit(xParts[1][0]) && !char.IsDigit(yParts[1][0]))
        return -1; // Digits go before non-digit.

    if (!char.IsDigit(xParts[1][0]) && char.IsDigit(yParts[1][0]))
        return 1; // Digits go before non-digit.

    return string.Compare(yParts[1], xParts[1], StringComparison.Ordinal);
}

Which you can then use to sort a string list, array or IEnumerable<string>, like so:

using System;
using System.Collections.Generic;
using System.Linq;

namespace Demo
{
    static class Program
    {
        static void Main()
        {
            var strings = new []
            {
                "AB1001_A",
                "AB1001_B",
                "AB1002_2",
                "AB1002_C",
                "AB1003_0",
                "AB1003_",
                "AB1003_B",
                "AB1003_A",
                "AB1001_0",
                "AB1001_1",
                "AB1001_2",
                "AB1001_C",
                "AB1002_B",
                "AB1002_A",
            };

            static int compare(string x, string y)
            {
                var xParts = x.Split('_', StringSplitOptions.RemoveEmptyEntries);
                var yParts = y.Split('_', StringSplitOptions.RemoveEmptyEntries);

                if (xParts.Length != yParts.Length)
                    return yParts.Length - xParts.Length;

                if (xParts.Length == 0)
                    return 0;

                int comp = string.Compare(xParts[0], yParts[0], StringComparison.Ordinal);

                if (comp != 0 || xParts.Length == 1)
                    return comp;

                if (char.IsDigit(xParts[1][0]) && !char.IsDigit(yParts[1][0]))
                    return -1; // Digits go before non-digit.

                if (!char.IsDigit(xParts[1][0]) && char.IsDigit(yParts[1][0]))
                    return 1; // Digits go before non-digit.

                return string.Compare(yParts[1], xParts[1], StringComparison.Ordinal);
            }

            var stringList = strings.ToList();
            stringList.Sort(compare);

            Console.WriteLine("Sorted list:");
            Console.WriteLine(string.Join("\n", stringList));

            var stringArray = strings.ToArray();
            Array.Sort(stringArray, compare);

            Console.WriteLine("\nSorted array:");
            Console.WriteLine(string.Join("\n", stringArray));

            var sequence = strings.Select(element => element);
            var sortedSeq = sequence.OrderBy(element => element, Comparer<string>.Create(compare));

            Console.WriteLine("\nSorted sequence:");
            Console.WriteLine(string.Join("\n", sortedSeq));
        }
    }
}

Try it online on .Net Fiddle

Matthew Watson
  • 104,400
  • 10
  • 158
  • 276
0

Finally I got the soln by this

var mystrings = new []
            {
                "AB1001_A",
                "AB1001_B",
                "AB1002_2",
                "AB1002_C",
                "AB1003_0",
                "AB1003_",
                "AB1003_B",
                "AB1003_A",
                "AB1001_0",
                "AB1001_1",
                "AB1001_2",
                "AB1001_C",
                "AB1002_B",
                "AB1002_A",
            };


mystrings.Cast<string>().OrderBy(x => PadNumbers(x));

and then PadNumbers function as like below

        public static string PadNumbers(string input)
        {
            return Regex.Replace(input, "[0-9]+", match => match.Value.PadLeft(10, '0'));
        }