Sort array of objects by single key with date value

后端 未结 19 1349
情话喂你
情话喂你 2020-11-22 10:56

I have an array of objects with several key value pairs, and I need to sort them based on \'updated_at\':

[
    {
        \"updated_at\" : \"2012-01-01T06:25         


        
相关标签:
19条回答
  • 2020-11-22 11:53

    With this we can pass a key function to use for the sorting

    Array.prototype.sortBy = function(key_func, reverse=false){
        return this.sort( (a, b) => {
            var keyA = key_func(a),
                keyB = key_func(b);
            if(keyA < keyB) return reverse? 1: -1;
            if(keyA > keyB) return reverse? -1: 1;
            return 0;
        }); 
    }
    

    Then for example if we have

    var arr = [ {date: "01/12/00", balls: {red: "a8",  blue: 10}},
                {date: "12/13/05", balls: {red: "d6" , blue: 11}},
                {date: "03/02/04", balls: {red: "c4" , blue: 15}} ]
    

    We can do

    arr.sortBy(el => el.balls.red)
    /* would result in
    [ {date: "01/12/00", balls: {red: "a8", blue: 10}},
      {date: "03/02/04", balls: {red: "c4", blue: 15}},
      {date: "12/13/05", balls: {red: "d6", blue: 11}} ]
    */
    

    or

    arr.sortBy(el => new Date(el.date), true)   // second argument to reverse it
    /* would result in
    [ {date: "12/13/05", balls: {red: "d6", blue:11}},
      {date: "03/02/04", balls: {red: "c4", blue:15}},
      {date: "01/12/00", balls: {red: "a8", blue:10}} ]
    */
    

    or

    arr.sortBy(el => el.balls.blue + parseInt(el.balls.red[1]))
    /* would result in
    [ {date: "12/13/05", balls: {red: "d6", blue:11}},    // red + blue= 17
      {date: "01/12/00", balls: {red: "a8", blue:10}},    // red + blue= 18
      {date: "03/02/04", balls: {red: "c4", blue:15}} ]   // red + blue= 19
    */
    
    0 讨论(0)
  • 2020-11-22 11:54

    Here's a slightly modified version of @David Brainer-Bankers answer that sorts alphabetically by string, or numerically by number, and ensures that words beginning with Capital letters don't sort above words starting with a lower case letter (e.g "apple,Early" would be displayed in that order).

    function sortByKey(array, key) {
        return array.sort(function(a, b) {
            var x = a[key];
            var y = b[key];
    
            if (typeof x == "string")
            {
                x = (""+x).toLowerCase(); 
            }
            if (typeof y == "string")
            {
                y = (""+y).toLowerCase();
            }
    
            return ((x < y) ? -1 : ((x > y) ? 1 : 0));
        });
    }
    
    0 讨论(0)
  • 2020-11-22 11:54

    With ES2015 support it can be done by:

    foo.sort((a, b) => a.updated_at < b.updated_at ? -1 : 1)
    
    0 讨论(0)
  • 2020-11-22 11:55

    Sorting by an ISO formatted date can be expensive, unless you limit the clients to the latest and best browsers, which can create the correct timestamp by Date-parsing the string.

    If you are sure of your input, and you know it will always be yyyy-mm-ddThh:mm:ss and GMT (Z) you can extract the digits from each member and compare them like integers

    array.sort(function(a,b){
        return a.updated_at.replace(/\D+/g,'')-b.updated_at.replace(/\D+/g,'');
    });
    

    If the date could be formatted differently, you may need to add something for iso challenged folks:

    Date.fromISO: function(s){
        var day, tz,
        rx=/^(\d{4}\-\d\d\-\d\d([tT ][\d:\.]*)?)([zZ]|([+\-])(\d\d):(\d\d))?$/,
        p= rx.exec(s) || [];
        if(p[1]){
            day= p[1].split(/\D/).map(function(itm){
                return parseInt(itm, 10) || 0;
            });
            day[1]-= 1;
            day= new Date(Date.UTC.apply(Date, day));
            if(!day.getDate()) return NaN;
            if(p[5]){
                tz= (parseInt(p[5], 10)*60);
                if(p[6]) tz+= parseInt(p[6], 10);
                if(p[4]== '+') tz*= -1;
                if(tz) day.setUTCMinutes(day.getUTCMinutes()+ tz);
            }
            return day;
        }
        return NaN;
    }
    if(!Array.prototype.map){
        Array.prototype.map= function(fun, scope){
            var T= this, L= T.length, A= Array(L), i= 0;
            if(typeof fun== 'function'){
                while(i< L){
                    if(i in T){
                        A[i]= fun.call(scope, T[i], i, T);
                    }
                    ++i;
                }
                return A;
            }
        }
    }
    }
    
    0 讨论(0)
  • 2020-11-22 11:56

    As This answer's states, you can use Array.sort.

    arr.sort(function(a,b){return new Date(a.updated_at) - new Date(b.updated_at)})

    arr = [
        {
            "updated_at" : "2012-01-01T06:25:24Z",
            "foo" : "bar"
        },
        {
            "updated_at" : "2012-01-09T11:25:13Z",
            "foo" : "bar"
        },
        {
            "updated_at" : "2012-01-05T04:13:24Z",
            "foo" : "bar"
        }
    ];
    arr.sort(function(a,b){return new Date(a.updated_at) - new Date(b.updated_at)});
    console.log(arr);

    0 讨论(0)
  • 2020-11-22 11:58

    Just another, more mathematical, way of doing the same thing but shorter:

    arr.sort(function(a, b){
        var diff = new Date(a.updated_at) - new Date(b.updated_at);
        return diff/(Math.abs(diff)||1);
    });
    

    or in the slick lambda arrow style:

    arr.sort((a, b) => {
        var diff = new Date(a.updated_at) - new Date(b.updated_at);
        return diff/(Math.abs(diff)||1);
    });
    

    This method can be done with any numeric input

    0 讨论(0)
提交回复
热议问题