Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
155 views
in Technique[技术] by (71.8m points)

javascript - 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?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...