Sort array of objects in specific order

前端 未结 5 1862
青春惊慌失措
青春惊慌失措 2021-02-11 03:51

I have an array of objects returning from an API call which I need to sort into a specific format.

I\'m trying to organise the destination_country_id alphab

相关标签:
5条回答
  • 2021-02-11 04:25

    Possibly not the most efficient method but it is ES3, doesn't require any libraries, and is fairly easy to understand. Also assuming you wanted to sort alphabetically on destination_country_name

    Javascript

    // where x is your array of objects
    x.sort(function (a, b) {
        // sorts everything alphabetically
        return a.destination_country_name.localeCompare(b.destination_country_name);
    }).sort(function (a, b) {
        // moves only this to country to top
        return +(!b.destination_country_name.localeCompare('United States'));
    }).sort(function (a, b) {
        // moves only this to country to top
        return +(!b.destination_country_name.localeCompare('United Kingdom'));
    }).sort(function (a, b) {
        // moves only this to country to top
        return +(!b.destination_country_name.localeCompare('Ireland'));
    }).sort(function (a, b) {
        // moves only this to country to bottom
        return +(!a.destination_country_name.localeCompare('Everywhere Else'));
    });
    
    console.log(JSON.stringify(x, ['destination_country_name']));
    

    Output

    [{"destination_country_name":"Ireland"},
     {"destination_country_name":"United Kingdom"},
     {"destination_country_name":"United States"},
     {"destination_country_name":"France"},
     {"destination_country_name":"Spain"},
     {"destination_country_name":"Everywhere Else"}]
    

    On jsFiddle

    We could even go a step further and use the above example to make a reusable function, like.

    Javascript

    function sorter(array, funcs, orders) {
        funcs = funcs || {};
        orders = orders || {};
        array.sort(funcs.general);
        if (Array.isArray(orders.top)) {
            orders.top.slice().reverse().forEach(function(value) {
                array.sort(funcs.top.bind(value));
            });
        }
    
        if (Array.isArray(orders.bottom)) {
            orders.bottom.forEach(function(value) {
                array.sort(funcs.bottom.bind(value));
            });
        }
    
        return array;
    }
    
    sorter(x, {
        general: function (a, b) {
            return a.destination_country_name.localeCompare(b.destination_country_name);
        },
        top: function (a, b) {
            return +(!b.destination_country_name.localeCompare(this));
        },
        bottom: function (a, b) {
            return +(!a.destination_country_name.localeCompare(this));
        }
    }, {
        top: ['Ireland', 'United Kingdom', 'United States'],
        bottom: ['Everywhere Else']
    });
    

    On jsFiddle

    And now you can easily sort on different attributes by parsing in different compare functions, and define values that should be at the top or bottom.

    I used ECMA5 methods but you could just as easily make it with ECMA3.

    0 讨论(0)
  • 2021-02-11 04:32

    You can give every object a 'sort-order' property. Specify the known first 3 and the last, and give all the others the same value, greater than the first three and less than the last. Then sort the array- first by sort-order, and then alphabetically;

    var arr= [{ "destination_country_id": null, "primary_cost": "9.50", "region_id": null, "destination_country_name": "Everywhere Else", },{ "destination_country_id": 105, "primary_cost": "8.00", "region_id": null, "destination_country_name": "United Kingdom", },{ "destination_country_id": 209, "primary_cost": "9.50", "region_id": null, "destination_country_name": "United States", },{ "destination_country_id": 123, "primary_cost": "5.00", "region_id": null, "destination_country_name": "Ireland", },{ "destination_country_id": 185, "primary_cost": "5.00", "region_id": null, "destination_country_name": "France", },{ "destination_country_id": 145, "primary_cost": "5.00", "region_id": null, "destination_country_name": "Spain", }]

    var s= "destination_country_name",
    order= ["Ireland", "United Kingdom", 
    "United States", "Everywhere Else"];
    
    arr.forEach(function(itm){
        var i= order.indexOf(itm[s]);
        if(i!= -1) itm.sort_order= i== 3? 1e50: i;
        else itm.sort_order= 10;
    });
    
    arr.sort(function(a, b){
        var d= a.sort_order- b.sort_order;
        if(d===0){
            if(a[s]=== b[s]) return 0;
            return a[s]>b[s]? 1: -1;
        }
        return d;
    });
    JSON.stringify(arr)
    /*  returned value: (String)[{
            "destination_country_id": 123, "primary_cost": "5.00", "region_id": null, 
            "destination_country_name": "Ireland", "sort_order": 0
        },{
            "destination_country_id": 105, "primary_cost": "8.00", "region_id": null, 
            "destination_country_name": "United Kingdom", "sort_order": 1
        },{
            "destination_country_id": 209, "primary_cost": "9.50", "region_id": null, 
            "destination_country_name": "United States", "sort_order": 2
        },{
            "destination_country_id": 185, "primary_cost": "5.00", "region_id": null, 
            "destination_country_name": "France", "sort_order": 10
        },{
            "destination_country_id": 145, "primary_cost": "5.00", "region_id": null, 
            "destination_country_name": "Spain", "sort_order": 10
        },{
            "destination_country_id": null, "primary_cost": "9.50", "region_id": null, 
            "destination_country_name": "Everywhere Else", "sort_order": 1e+50
        }
    ]
    */
    
    0 讨论(0)
  • 2021-02-11 04:36

    I think the most efficient way to sort your array is to first find where "Everywhere Else", the "UK", "Ireland", and the "US" are in your array, remove them, and then sort the rest of the array. This is simpler than it sounds

    fiddle

    var data = [
        {"destination_country_name": "Everywhere Else"},
        {"destination_country_name": "United Kingdom"},
        {"destination_country_name": "United States"},
        {"destination_country_name": "Ireland"},
        {"destination_country_name": "France"},
        {"destination_country_name": "Spain"}     ];
    //removed the other elements just to make the example cleaner
    var keep = ["Everywhere Else", "Ireland", "United Kingdom", "United States"];
    //keep is the elements you want in the front; order them exactly at you want them ordered
    var top = [];
    //this is our holder array to hold the objects for the strings in keep
    
    for (var i = 0; i < keep.length; i++) {
        var index = function () {
            for (var j = 0; j < data.length; j++){    //loop through data
                if (data[j].destination_country_name == keep[i])
                    return data[j];    //return the object if it's name matches the one in keep
            }
        }
        if (index > -1){        //if the object is in the array (index != -1)
            top.push(data[index]);    //push the object to our holder array
            data.splice(index, 1);    //splice the object out of the original array
        }
    }
    //after this loop, those other objects will have been removed
    //sort the rest of that array of objects
    data.sort(function (a, b) {    //use a callback function to specify which parts of
                                   //the object need to be sorted
        //basic sorting/compare algorithm (-1, 0, or 1)
        if (a.destination_country_name > b.destination_country_name)
            return 1;        //if greater
        if (a.destination_country_name < b.destination_country_name)
            return -1;        //if lesser
        return 0;    //otherwise
    })
    
    var sorted = top.concat(data), //combine data to the holder array and assign to sorted
        extra = sorted.shift();    //grab the first element ("Everywhere Else") and remove it
        sorted.push(extra);        //add that element to the end of the array
    console.log(sorted);
    

    Alternatively, if you know those four places (EE, UK, US, and Ireland) will always be the first 4 elements in your array, you can do the following:

    var data = [
        {"destination_country_name": "Everywhere Else"},
        {"destination_country_name": "United Kingdom"},
        {"destination_country_name": "United States"},
        {"destination_country_name": "Ireland"},
        {"destination_country_name": "France"},
        {"destination_country_name": "Spain"}     ];
    
    var top = data.slice(0,4);
    data.sort(function (a, b) {
        if (a.destination_country_name > b.destination_country_name)
            return 1;
        if (a.destination_country_name < b.destination_country_name)
            return -1;
        return 0;
    })
    
    var sorted = top.concat(data),
            extra = sorted.shift();
            sorted = sorted.push(extra);    //put "Everywhere Else" at the end of the array
    

    Note how this is much more efficient (and much simpler!) because you don't need to locate those four elements.

    0 讨论(0)
  • 2021-02-11 04:41

    you can use underscore sortBy method:

    a=[{obj:'first3'},{obj:'first2'},{obj:'first1'},{obj:'z'},{obj:'m'},{obj:'c'},{obj:'end3'},{obj:'end2'},{obj:'end1'}]
    a=_.sortBy(a,function (t,i){if (i<=2) return String.fromCharCode(0);if(i>=a.length-3) return String.fromCharCode(255);return t.obj })
    
    console.log(JSON.stringify(a))
    
    [{"obj":"first3"},{"obj":"first2"},{"obj":"first1"},{"obj":"c"},{"obj":"m"},{"obj":"z"},{"obj":"end3"},{"obj":"end2"},{"obj":"end1"}]
    

    http://jsfiddle.net/43Q8h/

    0 讨论(0)
  • 2021-02-11 04:41

    If your provided array is called list, you can sort it as you want using the following call:

    list.sort(function (item1, item2) {
        if (item1.destination_country_name < item2.destination_country_name) {
            return -1;
        }
        return 1;
    });
    
    0 讨论(0)
提交回复
热议问题