Reputation: 13367
I am trying to sort an array:
var mapped = [{
wiFi: true,
megapixel: '20 MP'
},{
wiFi: false,
megapixel: '25 MP'
},{
wiFi: true,
megapixel: '25 MP'
},{
wiFi: true,
megapixel: '21 MP'
}];
I would like to sort it on both properties (wiFi first). This is a really simple version of what I am doing, but the properties can be decided by the user, so I have a function that looks a bit like this:
var fields = ['wiFi', 'megapixel'];
// Sort our mapped array
mapped.sort(function (a, b) {
// Loop through our properties
fields.forEach(function (field) {
// Get our value (skip the first)
var x = a[field.name];
var y = b[field.name];
// Switch on the type
switch (typeof x) {
// Boolean
case "boolean":
// Return our value
return x === y ? 0 : x ? -1 : 1;
// Default
default:
// Return our value
return x === y ? 0 : x < y ? -1 : 1;
}
});
});
but my array is not being sorted at all. Does anyone know why?
Upvotes: 1
Views: 148
Reputation: 13367
Thanks to all your suggestions, I have tried to combine them all and come up with this:
// Sort our mapped array
mapped.sort(function (a, b) {
// Loop through our properties
for (var i = 0; i < fields.length; i++) {
// Get our field
var field = fields[i];
// Get our value (skip the first)
var x = a[field.name];
var y = b[field.name];
// If our values are the same, go to the next compare
if (x === y)
continue;
// Switch on the type
switch (field.type) {
// Boolean
case "boolean":
// Return our value
return x ? -1 : 1;
// Integer
case "float":
// Update our values
x = parseFloat(x);
y = parseFloat(y);
// Return our value
return x < y ? -1 : 1;
// Default (string)
default:
// Return our value
return x.localeCompare(y);
}
}
Upvotes: 0
Reputation: 386578
You can use sort with a helper object.
var mapped = [{ wiFi: true, megapixel: '20 MP' }, { wiFi: false, megapixel: '25 MP' }, { wiFi: true, megapixel: '25 MP' }, { wiFi: true, megapixel: '21 MP' }],
fields = ['wiFi', 'megapixel'],
types = {
wiFi: function (o) { return +!o.wiFi; }, // if true sort top
megapixel: function (o) { return parseFloat(o.megapixel) || 0; },
};
mapped.sort(function (a, b) {
var r = 0;
fields.some(function (c) {
return (r = types[c](a) - types[c](b));
});
return r;
});
document.write('<pre>' + JSON.stringify(mapped, 0, 4) + '</pre>');
Upvotes: 0
Reputation: 24915
You can try to compute rank and based on rank, you can sort values:
var mapped = [{ wiFi: true, megapixel: '20 MP'}, { wiFi: false, megapixel: '25 MP'}, { wiFi: true, megapixel: '25 MP'}, { wiFi: true, megapixel: '21 MP'}];
var fields = ['wiFi', 'megapixel'];
// Sort our mapped array
mapped.sort(function(a, b) {
var a_rank = 0;
var b_rank = 0;
// Loop through our properties
fields.forEach(function(field) {
// Get our value (skip the first)
var x = a[field];
var y = b[field];
// Switch on the type
switch (typeof x) {
// Boolean
case "boolean":
a_rank += x ? -10 : 10;
b_rank += y ? -10 : 10;
break;
// Default
default:
if (x > y) {
a_rank += 10;
b_rank -= 10;
} else if (y > x) {
a_rank -= 10;
b_rank += 10
}
break;
}
});
return a_rank > b_rank ? 1 : a_rank < b_rank ? -1 : 0
});
document.write("<pre>" + JSON.stringify(mapped,0,4)+ "</pre>")
Upvotes: 0
Reputation: 324640
Try a manual iteration instead of one that uses an inner function.
mapped.sort(function(a,b) {
var x, y, i, l = fields.length;
for( i=0; i<l; i++) {
x = a[fields[i]];
y = b[fields[i]];
if( x === y) continue; // proceed to next field to compare
switch(typeof x) {
case "boolean":
return x ? -1 : 1;
// could do other things, eg. case "string": return x.localeCompare(y);
default:
return x < y ? -1 : 1;
}
}
return 0; // all fields compared equal
});
Upvotes: 1