3

I've an array and I want to sort it by "id" and "date" from smaller to bigger. How can I do this correctly ?

Example :

var unsorted = [
    {id: 1, date: "2015-01-18T15:00:00+01:00"}, 
    {id: 1, date: "2015-01-18T14:30:00+01:00"}, 
    {id: 2, date: "2015-01-18T10:00:00+01:00"}, 
    {id: 1, date: "2015-01-18T16:00:00+01:00"}, 
    {id: 3, date: "2015-01-18T14:15:00+01:00"}, 
    {id: 2, date: "2015-01-18T14:00:00+01:00"}
]

Should return :

var sorted = [
    {id: 1, date: "2015-01-18T14:30:00+01:00"}, 
    {id: 1, date: "2015-01-18T15:00:00+01:00"}, 
    {id: 1, date: "2015-01-18T16:00:00+01:00"}, 
    {id: 2, date: "2015-01-18T10:00:00+01:00"}, 
    {id: 2, date: "2015-01-18T14:00:00+01:00"},
    {id: 3, date: "2015-01-18T14:15:00+01:00"} 
]
AstroCB
  • 12,337
  • 20
  • 57
  • 73
robpal
  • 846
  • 4
  • 10
  • 21

5 Answers5

7

Here is an example using array.sort:

var arr = [
    {id: 1, date: "2015-01-18T15:00:00+01:00"}, 
    {id: 1, date: "2015-01-18T14:30:00+01:00"}, 
    {id: 2, date: "2015-01-18T10:00:00+01:00"}, 
    {id: 1, date: "2015-01-18T16:00:00+01:00"}, 
    {id: 3, date: "2015-01-18T14:15:00+01:00"}, 
    {id: 2, date: "2015-01-18T14:00:00+01:00"}
];

arr.sort(function(a,b){
    if (a.id == b.id) return a.date.localeCompare(b.date);
    return a.id-b.id;    
});

// test
for (var i in arr) {
    console.log(arr[i]);
}

Result being:

 Object {id: 1, date: "2015-01-18T14:30:00+01:00"}
 Object {id: 1, date: "2015-01-18T15:00:00+01:00"}
 Object {id: 1, date: "2015-01-18T16:00:00+01:00"}
 Object {id: 2, date: "2015-01-18T10:00:00+01:00"}
 Object {id: 2, date: "2015-01-18T14:00:00+01:00"}
 Object {id: 3, date: "2015-01-18T14:15:00+01:00"}
MightyPork
  • 18,270
  • 10
  • 79
  • 133
  • 3
    Nice use of `localeCompare`. +1 – Mulan Jan 18 '15 at 19:38
  • Note that depending on how the date is formatted comparing the string representation does not give the same result as comparing the dates. See superpuccio's comment [here](http://stackoverflow.com/a/493018/4178025) for an example. – Diego Jan 18 '15 at 19:44
5

You can use .sort():

var unsorted = [
    {id: 1, date: "2015-01-18T15:00:00+01:00"}, 
    {id: 1, date: "2015-01-18T14:30:00+01:00"}, 
    {id: 2, date: "2015-01-18T10:00:00+01:00"}, 
    {id: 1, date: "2015-01-18T16:00:00+01:00"}, 
    {id: 3, date: "2015-01-18T14:15:00+01:00"}, 
    {id: 2, date: "2015-01-18T14:00:00+01:00"}
];

var sorted = unsorted.sort(function(a, b) {
    return a.id == b.id ?
        new Date(a.date) - new Date(b.date) : a.id - b.id;
});

console.log(sorted);

Output:

[ { id: 1, date: '2015-01-18T14:30:00+01:00' },
  { id: 1, date: '2015-01-18T15:00:00+01:00' },
  { id: 1, date: '2015-01-18T16:00:00+01:00' },
  { id: 2, date: '2015-01-18T10:00:00+01:00' },
  { id: 2, date: '2015-01-18T14:00:00+01:00' },
  { id: 3, date: '2015-01-18T14:15:00+01:00' } ]
James M
  • 18,506
  • 3
  • 48
  • 56
3

Give this a shot

var sorted = unsorted.sort(function(a, b) {
    return a.id === b.id ?
      Date.parse(a.date) - Date.parse(b.date) :
      a.id - b.id ;
});

Explanation

If the id field is equal, we want to return the comparison of the date field.

If the id field is not equal, we will return the comparison of the id field

Mulan
  • 129,518
  • 31
  • 228
  • 259
0

Array.sort takes a function with two parameters to compare two elements of an array. If this function returns a negative then a is placed before b, if it returns positive then a is placed before b and if it returns 0 they stay as they are. Here I compare them by id and if their IDs are same then I compare them by date.

var unsorted = [{
  id: 1,
  date: "2015-01-18T15:00:00+01:00"
}, {
  id: 1,
  date: "2015-01-18T14:30:00+01:00"
}, {
  id: 2,
  date: "2015-01-18T10:00:00+01:00"
}, {
  id: 1,
  date: "2015-01-18T16:00:00+01:00"
}, {
  id: 3,
  date: "2015-01-18T14:15:00+01:00"
}, {
  id: 2,
  date: "2015-01-18T14:00:00+01:00"
}];

unsorted.sort(function(a, b) {
  if (a.id < b.id)
    return -1;
  else if (a.id > b.id)
    return 1;
  else {
    if (a.date < b.date)
      return -1;
    else if (a.date > b.date)
      return 1;
    else
      return 0;
  }
});
Ozan
  • 3,709
  • 2
  • 18
  • 23
0

Divide and conquer!

Start by reducing the input array into a map of id => object, ie:

var dataById = unsorted.reduce(function (soFar, value) {
 // Initialise the array if we haven't processed this
    // id yet.
    if (soFar[value.id] === undefined) {
        soFar[value.id] = [];
    }
  
    // ad this object to Array.
    soFar[value.id].push(value);
  
    return soFar;
}, {});

Now you can sort each array by looping over the Object's keys, note this modifies the dataById map in place.

Object.keys(dataById).forEach(function (id) {
 dataById[id] = dataById[id].sort();
});

Finally, you can combine all the data together, again by iterating over the keys in the map. Note that maps (objects) in javascript don't guarantee the order of their keys, so you may wish to dump the ids out to an Array first before iterating:

var ids = Object.keys(dataById).sort();

// Reduce the ids into an Array of data.
var ids.reduce(function (soFar, value) {
 return soFar.concat(dataById[id]);
}, []);

Not the most efficient way of solving your problem, but hopefully it gives you some help with the thought process.

JonnyReeves
  • 6,119
  • 2
  • 26
  • 28