1

I have a following string list:

List<string> a = new List<string>();

a.Add("2015");
a.Add("2015 /M1");
a.Add("2015 /M2");
a.Add("2015 /M9");
a.Add("2015 /M10");
a.Add("2015 /M11");
a.Add("2015 /M12");
a.Add("2015 /M3");
a.Add("2015 /M4");
a.Add("2015 /M5");
a.Add("2015 /M6");
a.Add("2015 /M7");
a.Add("2015 /M8");

When I call the sort function a.sort() it sorts like this:

2015
2015 /M1
2015 /M11
2015 /M12
2015 /M2
2015 /M3
2015 /M4
2015 /M5
2015 /M6
2015 /M7
2015 /M8
2015 /M9

But how can I modify to make it look like below.

2015
2015 /M1
2015 /M2
2015 /M3
2015 /M4
2015 /M5
2015 /M6
2015 /M7
2015 /M8
2015 /M9
2015 /M10
2015 /M11
2015 /M12

I have same pattern in other list items as well like 2015 Q/12, 2015 Q/11 etc.

3
  • 2
    Implement IComparer interface and perform your custom sorting algorithm and pass that to the Sort method. MSDN is your friend. Commented Oct 26, 2016 at 5:09
  • is your input format always "yyyy X/MM", where yyyy is year, X is any random char, MM is month? The short answer to your problem is sort by int, not by string. Commented Oct 26, 2016 at 5:11
  • I need it to be done in string list as I have 2015 Q/1, 2015 Q/2 as well and these values are created dynamically. Commented Oct 26, 2016 at 5:14

6 Answers 6

2

You need to extract the number from string, it can be done by regex. Then convert it to integer and sort by it.

var e = from s in a
        let g = Regex.Match(s, @"^\d+(?: \/[MQ](\d+))?$")
        let n = g.Groups[1].Value != "" ? int.Parse(g.Groups[1].Value) : (int?)null
        orderby n
        select s;

a = e.ToList();

Edit

To sort by year first, then use following code

var e = from s in a
        let g = Regex.Match(s, @"^[A-Za-z]*(\d+)(?: \/[MQ](\d+))?$")
        let y = g.Groups[1].Value != "" ? int.Parse(g.Groups[1].Value) : 0
        let m = g.Groups[2].Value != "" ? int.Parse(g.Groups[2].Value) : 0                    
        orderby y, m      
        select s;
Sign up to request clarification or add additional context in comments.

7 Comments

What if want to sort 2015 Q/1 is same string along with 2015 M/1?
@Asim Do you want /Q1 to sort after /M1 or after /M3?
@NiyokoYuliawan I have tested your method and it solves the the months issue, show can I modify it to make it work for Q/1 as well.
@NiyokoYuliawan thanks, how can I modify it to add CY or FY at start like CY2015 /M1. It wil be either CY or FY in whole string. Thanks
@Asim Change your regex pattern to ^[A-Za-z]*\d+(?: \/[MQ](\d+))?$.
|
1

I did this:

var results =
    a
        .OrderBy(x => new string(x.Take(7).ToArray()))
        .ThenBy(x => int.Parse(new string(x.Skip(7).DefaultIfEmpty('0').ToArray())));

...and got this:

2015 
2015 /M1 
2015 /M2 
2015 /M3 
2015 /M4 
2015 /M5 
2015 /M6 
2015 /M7 
2015 /M8 
2015 /M9 
2015 /M10 
2015 /M11 
2015 /M12 

Comments

1

You are looking for natural sort order. In the linked question you can find a pure LINQ implementation which can be reused for any natural sort order problem.

Comments

0

This post was similar to yours. Edited as per your requirement:

var sortedList = a.OrderBy(x => PadNumbers(!x.Contains("M")? "" : x.Substring(x.IndexOf('M'), (x.Length - x.IndexOf('M'))))).ToList();

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

Comments

0

I have elaborated on Niyoko Yuliawans solution and the result is:

  class StringComparer : IComparer<string>
  {
    const string pattern = @"^\D*(?<year>\d{4})( \/[MQ](?<index>\d+))?$";

    public int Compare(string x, string y)
    {
      var mx = Regex.Match(x, pattern);
      var my = Regex.Match(y, pattern);

      int ix;
      if (int.TryParse(mx.Groups["index"].Value, out ix))
      {
        int iy;
        if (int.TryParse(my.Groups["index"].Value, out iy))
        {
          return ix.CompareTo(iy);
        }
      }

      return mx.Groups["year"].Value.CompareTo(my.Groups["year"].Value);
    }
  }

  class Program
  {
    static void Main(string[] args)
    {

      List<string> a = new List<string>();

      a.Add("2015");
      a.Add("2015 /Q1");
      a.Add("CY2015 /Q2");
      a.Add("2015 /Q9");
      a.Add("2015 /Q10");
      a.Add("2015 /Q11");
      a.Add("2015 /Q12");
      a.Add("2015 /Q3");
      a.Add("2014");
      a.Add("2015 /Q4");
      a.Add("2015 /Q5");
      a.Add("2015 /Q6");
      a.Add("2015 /Q7");
      a.Add("2015 /Q8");

      a.Sort(new StringComparer());

      foreach (var x in a)
      {
        Console.WriteLine(x);
      }

      Console.WriteLine("END");
      Console.ReadLine();

    }
  }

It avoids the temporary sequence (e).

Comments

-1

you can also write easily your own Extension for this sort function:

    public static class Extension
{
    public static List<string> sortItMyWay(this List<string> mylist)
    {
        string temp = string.Empty;

        for (int write = 0; write < mylist.Count; write++)
        {
            for (int sort = 0; sort < mylist.Count - 1; sort++)
            {
                if (mylist[sort].Weight() > mylist[sort + 1].Weight())
                {
                    temp = mylist[sort + 1];
                    mylist[sort + 1] = mylist[sort];
                    mylist[sort] = temp;
                }
            }
        }
        return mylist;
    }


public static int Weight (this string input)
{
    var value = 0;
    for (int i = input.Length - 1; i >= 0 ; i--)
    {
        value += input[i] * (int)Math.Pow(10,i);
    }
    return value;
}

}

3 Comments

How does this answer the question?
This is effectively sorting by string length? It fails if the string is too long (due to the `Math.Pow). It's not at all an obvious solution. Can you provide an explanation?
This weight function is giving a int value to each string. It is not sorting by lenght ! You are right concerning the restriction in Length, but it's ok for the question. This extension is maybe no best practice, but the questioner can change the Weight function the way he likes, for this question and for each other way of sorting he likes. In my opinion this has a much higher learning effect then just copying the regular expression, without getting how it works. The sortItMyWay function is just a bubble sort, using the weight function.

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.