HiveBrain v1.2.0
Get Started
← Back to all entries
snippetjavascriptMinor

Multicriteria sort array

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
arraysortmulticriteria

Problem

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?

Solution

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.

Code Snippets

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 ));

Context

StackExchange Code Review Q#47218, answer score: 4

Revisions (0)

No revisions yet.