Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sort array by date gives unexpected results

This will sound as an easy problem but I spent my Sunday trying to figure out what's wrong with my implementation described below so I am posting it to SO as a last resort.

I have a javascript application that receives data structures from a server. The server side sends the data unsorted for performance reasons.

Here is a snippet of the the javascript code receiving data:

    var seriesRawDataArray = ko.observableArray();     ...     analyticscontext.series(seriesRawDataArray).done(function () {         renderSeries();     }); 

The analyticscontext module queries the data using ajax:

function series(seriesData) {     return $.ajax({         url: "/api/analytics/series",         type: "GET",         success: function (data) {             return seriesData(data);         }     }); } 

The renderSeries performs a sort on the data before rendering it:

    // Sort the data by date using moment.js     seriesRawDataArray.sort(function (left, right) {         var leftDate = moment.utc(left.timeStamp);         var rightDate = moment.utc(right.timeStamp);         var diff = leftDate.diff(rightDate);         return diff > 0;     }); 

PROBLEM

Here is a data sample I receive from my server: enter image description here

Notice the unsorted items at the end. the seriesRawDataArray.sort seem to have no effect on the original array which does not get sorted no matter what I change in the sorting method. The output is always:

enter image description here

Notice the unsorted elements here. The libraries I am using and the data is definitely not the problem as this jsfiddle works just fine! Is there something wrong with this code?

like image 299
GETah Avatar asked Jan 18 '15 18:01

GETah


People also ask

How do you sort dates in moments?

sort(function(a, b){ return moment(b). format('X')-moment(a). format('X') }); Since moment can format valid dates the best way is to use the sort method javascript, so when formatting the date to timestamp, basically you sort by number.

How to sort in ascending order array in JavaScript?

JavaScript Array sort() The sort() sorts the elements of an array. The sort() overwrites the original array. The sort() sorts the elements as strings in alphabetical and ascending order.

Do JavaScript arrays maintain order?

JavaScript arrays have a defined order from index 0 to the last item in the list, and items added to the array using . push() stay in the order they are added in. That's what's meant by the term “insertion order.”

How does sort() work with numbers in JavaScript?

The sort() method sorts the elements of an array in place and returns the reference to the same array, now sorted. The default sort order is ascending, built upon converting the elements into strings, then comparing their sequences of UTF-16 code units values.


1 Answers

short answer

You should return the difference between the two dates, not a boolean:

// sort the data by date using moment.js seriesRawDataArray.sort(function (left, right) {     return moment.utc(left.timeStamp).diff(moment.utc(right.timeStamp)) }); 

why

Array.prototype.sort expects a negative, zero, or positive value to be returned. Generally, you'll write a sort function like this:

yourArray.sort(function (a, b) {     if (a < b) {            // a comes first         return -1     } else if (b < a) {     // b comes first         return 1     } else {                // equal, so order is irrelevant         return 0            // note: sort is not necessarily stable in JS     } }) 

The anonymous function passed to sort serves as the comparator for the native implementation of the sort function.

However, your negative value doesn't have to be -1 and your positive value doesn't have to be +1. Therefore, when sorting numbers, you can instead use the shortcut:

yourArray.sort(function (a, b) {     return a - b }) 

In JavaScript, subtracting two dates coerces them both into numbers, which is why we could use return moment.utc(left.timeStamp).diff(moment.utc(right.timeStamp))

(instead of direct subtraction -, this method uses moment.prototype.diff from the moment.js library)

However, in your code, you returned diff > 0, which can be either true or false. Because of type coercion, JavScript will read true as 1 and false as 0. This means your sort function will never return -1. Therefore, your elements will not be sorted correctly.

like image 183
royhowie Avatar answered Sep 20 '22 11:09

royhowie