Reputation: 668
I have a javascript array which looks like this:
var data = ["size64_tolPercent0.01_best", "size256_tolPercent0.01_best", "size256_tolPercent0_worst", "sizemax_tolPercent0_worst", "size1518_tolPercent0_worst", "size64_tolPercent0.01_worst", "size512_tolPercent0.01_worst", "size1518_tolPercent0.01_worst", "size256_tolPercent0_best"] etc
I want to sort this array :
So, we end up with a result array which looks like this:
["size64_tolPercent0_best", "size256_tolPercent0_best", "size512_tolPercent0_best", "size1518_tolPercent0_best", "sizemax_tolPercent0_best", "size64_tolPercent0.01_best", "size512_tolPercent0.01_best", "size1518_tolPercent0.01_best", "size64_tolPercent0_worst", "size256_tolPercent0_worst", "size512_tolPercent0_worst", "size1518_tolPercent0_worst", "sizemax_tolPercent0_worst"] etc
I am able to sort the strings using one of the methods but not all.
Here's what I've tried so far, I'm doing it wrong I'm sure, just need some help in the right direction. Doing it for 1 and 3 now:
var someLargeValue = 10000000;
data.sort(function(x,y){
var xp = x.substr(getPosition(x, '_', 2) + 1, x.split("_").pop().length);
var yp = y.substr(getPosition(y, '_', 2) + 1, y.split("_").pop().length);
return xp == yp ? 0 : xp < yp ? -1 : 1;
});
data.sort(function(x,y){
var xp = x.substr(4, getPosition(x, '_', 1) - 4);
var yp = y.substr(4, getPosition(y, '_', 1) - 4);
if(xp === "max") {
xp = someLargeValue;
}
if(yp === "max") {
yp = someLargeValue;
}
xp = parseInt(xp);
yp = parseInt(yp);
return xp == yp ? 0 : xp < yp ? -1 : 1;
});
function getPosition(str, m, i) {
return str.split(m, i).join(m).length;
}
But i'm afraid the code i'm trying is doing the sorting sequentially.. so what the first custom sort method is overridden by the second, I think?
Any help much appreciated.
Upvotes: 1
Views: 1039
Reputation: 386600
This solution features the Sorting with map from MDN.
First build a mapped array with splitted items for sorting. Then sort it by the custom order.
function (a, b) {
return a.rating.localeCompare(b.rating) ||
a.tolPercents - b.tolPercents ||
a.size - b.size;
}
Altogether:
var data = [
"size64_tolPercent0.01_best",
"size256_tolPercent0.01_best",
"size256_tolPercent0_worst",
"sizemax_tolPercent0_worst",
"size1518_tolPercent0_worst",
"size64_tolPercent0.01_worst",
"size512_tolPercent0.01_worst",
"size1518_tolPercent0.01_worst",
"size256_tolPercent0_best"
],
result = data.map(function (el, i) {
var a = /^size(.+)_tolpercent(.+)_(.+)$/i.exec(el);
return {
index: i,
rating: a[3],
tolPercents: a[2],
size: a[1] === 'max' ? Number.MAX_VALUE : a[1]
};
}).sort(function (a, b) {
return a.rating.localeCompare(b.rating) || a.tolPercents - b.tolPercents || a.size - b.size;
}).map(function (el) {
return data[el.index];
});
document.write('<pre>' + JSON.stringify(result, 0, 4) + '</pre>');
Upvotes: 2
Reputation:
I would first split the strings in order to minimize the amount of work done by the comparison function, as well as make it more readable. Then, I would recreate the strings once the array is sorted. Using a map is smarter though: https://stackoverflow.com/a/32379540/1636522 :-D
var data = ["size64_tolPercent0_best", "size256_tolPercent0_best", "size512_tolPercent0_best", "size1518_tolPercent0_best", "sizemax_tolPercent0_best", "size64_tolPercent0.01_best", "size512_tolPercent0.01_best", "size1518_tolPercent0.01_best", "size64_tolPercent0_worst", "size256_tolPercent0_worst", "size512_tolPercent0_worst", "size1518_tolPercent0_worst", "sizemax_tolPercent0_worst"];
// split the strings
var re = /max|\d+(?:\.\d+)?(?=_)|[^_]+$/g;
data = data.map(function (x) {
x = x.match(re); // example: ["64", "0.01", "best"]
if (x[0] !== 'max') x[0] = parseInt(x[0], 10);
x[1] = parseFloat(x[1]);
return x;
});
// sort the array
data.sort(function cmp (a, b) {
// 1. "best" and "worst"
if (a[2] > b[2]) return 1;
if (a[2] < b[2]) return -1;
// 2. percent
if (a[1] > b[1]) return 1;
if (a[1] < b[1]) return -1;
// 3. size
if (a[0] === 'max') return 1;
if (b[0] === 'max') return -1;
if (a[0] > b[0]) return 1;
if (a[0] < b[0]) return -1;
// 4. no differences
return 0;
});
// recreate the strings
data = data.map(function (x) {
x[0] = 'size' + x[0];
x[1] = 'tolPercent' + x[1];
return x.join('_');
});
// print the result
data.forEach(function (x) {
document.write(x + '<br />');
});
* {font-family:Courier}
Upvotes: 2
Reputation: 74
The Array class has a sort function: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort
Leverage the compare
argument:
data.sort(function(a, b) {
// Follow the docs as per how a relates to b, returning -1 (a < b),0 (equal) or 1 (a > b)
});
Extract and compare the sub strings as required in the function.
Update
After reading your code that you added, don't call sort() twice, just incorporate all the comparisons into the same sort comparison. Stop at the first inequality (aValue !== bValue
) and return that comparison.
Upvotes: -1