robpal
robpal

Reputation: 834

JavaScript sort array by 2 values

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"} 
]

Upvotes: 3

Views: 575

Answers (5)

JonnyReeves
JonnyReeves

Reputation: 6209

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.

Upvotes: 0

MightyPork
MightyPork

Reputation: 18861

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"}

Upvotes: 7

Mulan
Mulan

Reputation: 135247

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

Upvotes: 3

James M
James M

Reputation: 16718

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' } ]

Upvotes: 5

Ozan
Ozan

Reputation: 3739

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;
  }
});

Upvotes: 0

Related Questions