8

I have the array as below,

let  yearAndMonth  =  [
    { "year": 2013, "month": "FEBRUARY" },
    { "year": 2015, "month": "MARCH" },
    { "year": 2013, "month": "JANUARY" },
    { "year": 2015, "month": "FEBRUARY" }
]

I want to sort the array by year first and after that sort month from the year,

I want the output like this,

yearAndMonth  =  [
    { "year": 2013, "month": "JANUARY " },
    { "year": 2013, "month": "FEBRUARY" },
    { "year": 2015, "month": "FEBRUARY" },
    { "year": 2015, "month": "MARCH" }
]

How to achieve this?

Mohammad Usman
  • 37,952
  • 20
  • 92
  • 95
Aniket Avhad
  • 4,025
  • 2
  • 23
  • 29
  • Possible duplicate of [Sort array by firstname (alphabetically) in Javascript](https://stackoverflow.com/questions/6712034/sort-array-by-firstname-alphabetically-in-javascript) – RiaD Aug 18 '18 at 12:13
  • This question solution not an quite easy, but still many people posting this as duplicate with others..stupid things. finally accepted solution very fine working with me....Thank you everyone for help – Aniket Avhad Aug 18 '18 at 12:19

7 Answers7

5

You could take an object for the month names and their numerical value.

The chain the order by taking the delta of year and month.

var array =  [{ year: 2013, month: "FEBRUARY" }, { year: 2015, month: "MARCH" }, { year: 2013, month: "JANUARY" }, { year: 2015, month: "FEBRUARY" }];

array.sort(function (a, b) {
    var MONTH = { JANUARY: 0, FEBRUARY: 1, MARCH: 2, APRIL: 3, MAY: 4, JUNE: 5, JULY: 6, AUGUST: 7, SEPTEMBER: 8, OCTOBER: 9, NOVEMBER: 10, DECEMBER: 11 };
    return a.year - b.year || MONTH[a.month] - MONTH[b.month];
});

console.log(array);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
2

You can create an array for months names and sort like this:

let data = [
  { "year": 2013, "month": "FEBRUARY" }, { "year": 2015, "month": "MARCH" },
  { "year": 2013, "month": "JANUARY" }, { "year": 2015, "month": "FEBRUARY" }
];

let months = ["JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
              "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER"];

data.sort(
 (a, b) => (a.year - b.year) || (months.indexOf(a.month) - months.indexOf(b.month))
);


console.log(data);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Mohammad Usman
  • 37,952
  • 20
  • 92
  • 95
1

You can make a map which maps the Month to the month number and then use Arrays.sort() with your own custom comparator :

let months = { 'JANUARY' : 1, 'FEBRUARY' : 2, 'MARCH' : 3, 'APRIL' : 4, 'MAY' : 5, 'JUNE' : 6, 'JULY' : 7, 'AUGUST' : 8, 'SEPTEMBER' : 9, 'OCTOBER' : 10, 'NOVEMBER' : 11, 'DECEMBER' : 12 };
let  yearAndMonth  =  [ { "year": 2013, "month": "FEBRUARY" }, { "year": 2015, "month": "MARCH" }, { "year": 2013, "month": "JANUARY" }, { "year": 2015, "month": "FEBRUARY" } ];

yearAndMonth.sort((a,b)=> a.year - b.year || months[a.month.toUpperCase()] - months[b.month.toUpperCase()]);

console.log(yearAndMonth);
amrender singh
  • 7,949
  • 3
  • 22
  • 28
1

Since you are ok with using lodash this can be achived by a simple sortBy

_.sortBy(yearAndMonth, a => new Date(1+ a.month + a.year))

It will construct a new Date for each month and year (with date 1) and that should work the way you want.

let  yearAndMonth  =  [
    { "year": 2013, "month": "FEBRUARY" },
    { "year": 2015, "month": "MARCH" },
    { "year": 2013, "month": "JANUARY" },
    { "year": 2015, "month": "FEBRUARY" }
]

let res = _.sortBy(yearAndMonth, a => new Date(1 + a.month + a.year));
console.log('Sorted Result: ', res);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.10/lodash.min.js"></script>

Note: You do not need to have array/object/map of all the months for this to have a look up to perform > or <

Koushik Chatterjee
  • 4,106
  • 3
  • 18
  • 32
0

You can also use lodash library for sorting data by multiple column.

I have created a demo on Stackblitz. I hope this will help/guide to you/others.

lodash - Documentation

Component.html

<table width="100%">
  <tr>
    <td>Year</td>
    <td>Month</td>
  </tr>
  <tr *ngFor="let datas of sortedData">
    <td>{{datas.year}}</td>
    <td>{{datas.month}}</td>
  </tr>
</table>

Component.ts

 sortedData: any[];
  data = [
    { "year": 2013, "month": "FEBRUARY" },
    { "year": 2015, "month": "MARCH" },
    { "year": 2013, "month": "JANUARY" },
    { "year": 2013, "month": "MARCH" },
    { "year": 2013, "month": "APRIL" },
    { "year": 2015, "month": "FEBRUARY" }
  ];

monthArray: any = ["JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
        "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER"];

  ngOnInit() {
    this.sortedData = _.orderBy(data, [(datas) => datas.year, (user) => (this.monthArray.indexOf(user.month))], ["asc", "asc"]);
    console.log(this.sortedData);
  }
Aniket Avhad
  • 4,025
  • 2
  • 23
  • 29
Krishna Rathore
  • 9,389
  • 5
  • 24
  • 48
  • Thanks you for providing solution with lodash library. – Aniket Avhad Aug 18 '18 at 09:51
  • 4
    Rather than importing an entire library to do a basic thing like sorting, try [Vanilla JS](http://vanilla-js.com/): `data.sort(function(a,b) {return (a.year - b.year) || (monthArray.indexOf(a.month) - monthArray.indexOf(b.month));})` – Niet the Dark Absol Aug 18 '18 at 16:05
  • @NiettheDarkAbsol I agree it's overkill, but if he is using the library already for other purposes, `_.orderBy()` is also simple. – Armfoot Aug 18 '18 at 18:00
0

Declaring the month names in an array to get the relative value of the month string when comparing with each other.

First comparison will be on the year, if both the year values are same then proceeding with the month comparison based on the months array created.

let months = ["JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
          "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER"];



yearAndMonth.sort((a,b) =>{
    if(a.year > b.year) return 1;
    else if(a.year <  b.year) return -1;
    else {
        if(months.indexOf(a.month.toUpperCase()) > 
           months.indexOf(b.month.toUpperCase()))
               return 1;
        else if(months.indexOf(a.month.toUpperCase()) < 
         months.indexOf(b.month.toUpperCase())) 
               return -1
        else return 0;
  }
});
Fullstack Guy
  • 16,368
  • 3
  • 29
  • 44
0

See also: JsFiddle

Allow me to provide a plain ES version (sort array of objects on 1 or more key values, serial dependant (sort on 1, sort 2 within 1, sort on 3 within 1 and 2 etc.), non mutating, i.e. keep the original array as is):

const log = (...str) => 
  document.querySelector("pre").textContent += `${str.join("\n")}\n`;
const data = getData();
const xSort = XSort();
const months = [ "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE",
    "JULY", "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER" ];

log( JSON.stringify(
    xSort
    .create(data)
    .orderBy( {key: "year"}, { key: v => months.indexOf(v.month) } ),
    null,
    " ")
  );

function XSort() {
  const multiSorter = sortKeys => {
    if (!sortKeys || sortKeys[0].constructor !== Object) {
      throw new TypeError("Provide at least one {key: [keyname]} to sort on");
    }
    return function (val0, val1) {
      for (let sortKey of sortKeys) {
        const v0 = sortKey.key instanceof Function ? sortKey.key(val0) : val0[sortKey.key];
        const v1 = sortKey.key instanceof Function ? sortKey.key(val1) : val1[sortKey.key];
        const isString = v0.constructor === String || v1.constructor === String;
        const compare = sortKey.descending ?
          isString ? v1.toLowerCase().localeCompare(v0.toLowerCase()) : v1 - v0 :
          isString ? v0.toLowerCase().localeCompare(v1.toLowerCase()) : v0 - v1;
        if (compare !== 0) {
          return compare;
        }
      }
    };
  }
  const Sorter = function (array) {
    this.array = array;
  };

  Sorter.prototype = {
    orderBy: function(...sortOns) {
      return this.array.slice().sort(multiSorter(sortOns));
    },
  };

  return {
    create: array => new Sorter(array)
  };
}

function getData() {
  return [{
      "year": 2013,
      "month": "FEBRUARY",
    },
    {
      "year": 2015,
      "month": "MARCH",
    },
    {
      "year": 2015,
      "month": "SEPTEMBER",
    },
    {
      "year": 2013,
      "month": "JANUARY",
    },
    {
      "year": 2013,
      "month": "MARCH",
    },
    {
      "year": 2013,
      "month": "APRIL",
    },
    {
      "year": 2015,
      "month": "FEBRUARY",
    }
  ];
}
<pre></pre>
KooiInc
  • 119,216
  • 31
  • 141
  • 177