1

I have an array of objects containing integer representations of years/months:

[
   {
      year : 2014,
      month : 10
   },
   { 
     year : 2011,
     month : 6
   },
   {
     year : 2014,
     month : 11
   }
]

I need to sort them by month and year so that the most recent object is first.

Currently I am performing two sorts in order to achieve this:

        items.sort(function(a, b){
            if (a.month === b.month) {
                return 0;
            } else if (b.month > a.month) {
                return 1;
            }
            return -1;
        });

        items.sort(function(a, b){
            if (a.year === b.year) {
                return 0;
            } else if (b.year > a.year) {
                return 1;
            }
            return -1;
        });

First I am sorting by the month, then I am sorting by the year.

Although this works fine, it seems a bit hacky. How can I sort this array correctly using a single sort function?

Thanks in advance.

gordyr
  • 6,078
  • 14
  • 65
  • 123
  • possible duplicate of [How to sort an array of objects by multiple fields?](http://stackoverflow.com/questions/6913512/how-to-sort-an-array-of-objects-by-multiple-fields) – Felix Kling Mar 20 '14 at 01:43

3 Answers3

2

You could do like below:

items.sort(function(a, b){
  return a.year === b.year ? b.month - a.month : b.year - a.year;
});
xdazz
  • 158,678
  • 38
  • 247
  • 274
1

JavaScript's sort works like this

  1. first item is greater than the second item, if it receives a positive number

  2. first item is smaller than the second item, if it receives a negative number

  3. and zero if they both are the same.

So, we compare the years first. If they are the same, the we return the difference between the second's month and first's month. If the years are not the same, then we return the difference between the years.

    items.sort(function(first, second) {
        if (first.year === second.year) {
            return second.month - first.month;
        }
        return second.year - first.year;
    });

Output

[ { year: 2014, month: 11 },
  { year: 2014, month: 10 },
  { year: 2011, month: 6 } ]
thefourtheye
  • 233,700
  • 52
  • 457
  • 497
  • Thanks. Although the other answers are shorter in terms of code I will award it to you as soon as I am able for the comprehensive explanation. Anyway, cheers. it's actually frighteningly simply! :) – gordyr Mar 20 '14 at 01:39
  • Having looked further, all these answers seem to fail in Chrome. Apparently Chromes sorting algorithm differs from Firefox/IE's. Is there any way to make this cross browser? – gordyr Mar 20 '14 at 02:10
  • @gordyr I am checking, please give me a moment. – thefourtheye Mar 20 '14 at 02:59
  • It appears to be due to Chrome not using stable sort, whereas all other mainstream browsers do. Very frustrating. – gordyr Mar 20 '14 at 03:00
  • @gordyr Actually, Chrome internally uses v8 engine. I tested this code before posting in Node.js, which also uses v8 engine only. So, I am kinda confused. Investigating.... – thefourtheye Mar 20 '14 at 03:02
  • @gordyr Can you please try again. I am not able to reproduce this in my Chrome :( – thefourtheye Mar 20 '14 at 03:48
  • i've worked it where the problem stems from. For the most part the code will work which is why you cannot recreate the issue. The problem is only with certain datasets. Take a look here: https://code.google.com/p/v8/issues/detail?id=90 – gordyr Mar 20 '14 at 03:51
0

Like this:

items.sort(function(a, b) {
  return a.year - b.year || a.month - b.month;
});
sabof
  • 8,062
  • 4
  • 28
  • 52