4
\$\begingroup\$

I have an array of objects that I must sort based on two criteria. I've come up with a solution but I'd like to know if there is a better way to do it.

Assume a list of devices:

[
    {"battery_level": 0.45, "network_status": "ok"},
    {"battery_level": 0.45, "network_status": "ok"},
    {"battery_level": 0.50, "network_status": "lost"},
    {"battery_level": 0.35, "network_status": "lost"},
    {"battery_level": 0.75, "network_status": "ok"},
    {"battery_level": 0.05, "network_status": "lost"},
    {"battery_level": 0.75, "network_status": "lost"}
]

All lost devices must be on top and sorted by battery status ascending, so that it looks like this once sorted:

[
    {"battery_level":0.05,"network_status":"lost"},
    {"battery_level":0.35,"network_status":"lost"},
    {"battery_level":0.5,"network_status":"lost"},
    {"battery_level":0.75,"network_status":"lost"},
    {"battery_level":0.75,"network_status":"ok"},
    {"battery_level":0.45,"network_status":"ok"},
    {"battery_level":0.45,"network_status":"ok"}
]

Demo here

var devices = JSON.parse(document.getElementById('devices').innerHTML),
    lostDevices,
    sortBatteryLevelAsc,
    sortNetworkStatusLostAsc,
    i;

devices.sort(function (dev0, dev1) {
    return dev0.network_status === 'lost' ? -1 : 1;
});


lostDevices = devices.filter(function (dev) {
    return dev.network_status === 'lost';
});

lostDevices.sort(function (dev0, dev1) {
    return dev0.battery_level <= dev1.battery_level ? -1 : 1;
});

console.clear();
console.log(devices);

Array.prototype.splice.apply(devices, [0, lostDevices.length].concat(lostDevices));

console.log(devices);

Is it smart enough, or is there a smarter way to do it?

\$\endgroup\$

2 Answers 2

4
\$\begingroup\$

There is a better way, use a single sort function where you check on both values. If network status is different, sort on that, otherwise sort on battery power:

var devices = JSON.parse(document.getElementById('devices').innerHTML);

function sortDevicesByStatusAndPower(a, b) {
    var aStatus = a.network_status,
        bStatus = b.network_status;
    if( aStatus != b.network_status )
      return aStatus < bStatus ? -1 : 1;
    else
     return a.battery_level - b.battery_level;   
}

console.clear();

console.log(devices.sort( sortDevicesByStatusAndPower ));

I built a jsbin for this: http://jsbin.com/gesoq/1/edit

Finally, storing the JSON iside a script tag is .. novel, not sure it is the best approach.

\$\endgroup\$
1
  • \$\begingroup\$ Yes it was just to test my algorithm, in real situation I use an API with angular, but I considered it not relevant to the related problem. \$\endgroup\$
    – axelduch
    Commented Apr 15, 2014 at 12:03
2
\$\begingroup\$

If you're looking for tersity, here's another;

devices.sort(function(a, b) { 
    return a.network_status === b.network_status 
        ? a.battery_level - b.battery_level 
        : a.network_status > b.network_status;
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.