-1

I want to sort the list: (2012-09, 2012-10,2012-11,2012-12,2013-01, 2013-02,2013-03,2013-04,2013-05, 2013-06,2013-07,2013-08)

into a new list (2013-01, 2013-02, 2013-03, 2013-04 etc etc, 2012-09, 2012-10)

how can I do this in C#?

Bohrend
  • 1,467
  • 3
  • 17
  • 26

4 Answers4

4

Try this:

var sorted = notSorted.OrderByDescending(x => x.Year).ThenBy(x => x.Month).ToList();

It will sort your DateTimes (I assume that they are DateTimes), first on Year descending then on Month ascending, so it will produce that list you are expecting

If they are not DateTimes you can parse them using DateTime.Parse or DateTime.ParseExact

Read more about OrderBy and ThenBy

Kamil Budziewski
  • 22,699
  • 14
  • 85
  • 105
  • `var sorted = list.ToList(); sorted.Sort();` will be enough I think – Sriram Sakthivel Sep 19 '13 at 13:00
  • @SriramSakthivel: Huh, why? OP wants to order by year first, but in descending order, so highest years first, then he wants to order by month, so that each year keeps ascending order internally. `list.ToList` just creates a new list with the same content and order as before whereas `sorted.Sort()` will sort the original list but lowest years first. – Tim Schmelter Sep 19 '13 at 13:02
  • @TimSchmelter Ah, I missed Looking through it I thought he just explains how sorted looks like, but I didn't noticed the sort behavior is custom – Sriram Sakthivel Sep 19 '13 at 13:04
0

If your list does not contain datetime objects but insteads strings, you could order them the following way:

var unsortedArray = new string[] { "2012 - 09", "2012 - 10", "2012 - 11", "2012 - 12", "2013 - 01", "2013 - 02", "2013 - 03", "2013 - 04", "2013 - 05", "2013 - 06", "2013 - 07", "2013 - 08" };
var sortArray = unsortedArray.Select(x =>
{
    var split = x.Split(new string[] { " - " }, StringSplitOptions.None);
    return new { Original = x, Year = split[0], Month = split[1] };
})
.OrderByDescending(x => x.Year)
.ThenBy(x => x.Month)
.Select(x => x.Original)
.ToArray();
SynerCoder
  • 12,493
  • 4
  • 47
  • 78
  • I'm unamazed of this approach. It presumes a lot. The months must have always two digits, the separator must be `" - "`, there is always a month at all, so no invalid data. The best approach is to `TryParse` the strings to `DateTime`, use [wudzik's](http://stackoverflow.com/a/18895163/284240) order. – Tim Schmelter Sep 19 '13 at 13:26
  • @TimSchmelter indeed it presumes a lot. But then again I don't know the situation. It can be in a situation where you can make those asumption. Maybe a function just created those strings. If month single digit is an issue you can always use `.PadLeft(2,'0')`. This is just an option to sort the list. – SynerCoder Sep 19 '13 at 13:32
0

If list is a List<string> you can use following code

lst = lst.OrderByDescending(a => a.Substring(0, 4)).OrderBy(a => a.Substring(5, 2)).ToList();
Andy
  • 332
  • 1
  • 13
  • You have forgotten the separator `-` between year and month. Also, this does order lexicographically which means "9" is higher than "10", in case that the months do not necessarily have two digits. It is also not safe if the input might contain invalid data. – Tim Schmelter Sep 19 '13 at 13:22
0

You could create your own implementation of IComparer to deal with this which may allow more maintainability should your data structure change.

Here's a crude example to work with your provided example.

public class MonthYearStringComparer : 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;

        int[] xArray = x.Split('-').Select(xVal => int.Parse(xVal)).ToArray();
        int[] yArray = y.Split('-').Select(yVal => int.Parse(yVal)).ToArray();

        // x year is earlier
        if (xArray[0] < yArray[0]) return 1;
        // y year is earlier
        if (xArray[0] > yArray[0]) return -1;

        // years are same
        // x month is earlier
        if (xArray[1] < yArray[1]) return 1;
        // y month is earlier
        if (xArray[1] > yArray[1]) return -1;

        // same
        return 0;
    }

http://msdn.microsoft.com/en-us/library/234b841s.aspx

Then all you have to is instantiate your sorter and use it as a parameter in the sort method.

MonthYearStringComparer comparer = new MonthYearStringComparer();
myListOfYearAndMonthStrings.Sort(comparer);
Rich
  • 141
  • 1
  • 6