Reputation: 1336
I'm trying to sort array using a function. But when the number is going to two digit sorting is not correct. Otherwise it's showing correct result. Please check the code.
this is the function:
var arr = [{name: "a1", value: 1},{name: "a3", value: 1},{name: "a4", value: 1},{name: "a2", value: 1}];
var arr2 = [{name: "a1", value: 1},{name: "a3", value: 1},{name: "a14", value: 1},{name: "a12", value: 1}];
var sort = function (prop, arr) {
prop = prop.split('.');
var len = prop.length;
arr.sort(function (a, b) {
var i = 0;
while( i < len ) {
a = a[prop[i]];
b = b[prop[i]];
i++;
}
if (a < b) {
return -1;
} else if (a > b) {
return 1;
} else {
return 0;
}
});
return arr;
};
arr = sort('name', arr);
arr2 = sort('name', arr2);
console.log(arr); // it's correct
console.log(arr2); // it's not correct
In this case I'm trying to sort the array based on value of name
.
Upvotes: 0
Views: 111
Reputation: 28989
You can use numeric collation with String#localeCompare
. It will avoid lexicographic sorting and give you proper numeric order:
var a = "10";
var b = "2";
console.log( //false - string "10" does not come after "2" because 1 < 2
"a > b:",
a > b
);
console.log( //-1 - `a` comes before `b`
"a.localeCompare(b):",
a.localeCompare(b)
);
console.log( // 1 - `a` comes after `b`
"a.localeCompare(b, undefined, {numeric: true}):",
a.localeCompare(b, undefined, {numeric: true})
);
Note that this works for strings. If you also want to sort numbers, you have two easy options:
if
to check for what you're comparing and apply the .localeCompare
logic for strings and a different logic for numbers.Both would work but I personally prefer the first one, since it doesn't involve maintaining different cases. Thus using it in your solution gives the correct results:
var arr = [{name: "a1", value: 1},{name: "a3", value: 1},{name: "a4", value: 1},{name: "a2", value: 1}];
var arr2 = [{name: "a1", value: 1},{name: "a3", value: 1},{name: "a14", value: 1},{name: "a12", value: 1}];
var arr3 = [{name: "a", value: 3},{name: "a", value: 1},{name: "a", value: 14},{name: "a", value: 12}];
var sort = function (prop, arr) {
prop = prop.split('.');
var len = prop.length;
arr.sort(function (a, b) {var i = 0;
while( i < len ) {
a = a[prop[i]];
b = b[prop[i]];
i++;
}
//cast to string
a = String(a);
b = String(b);
return a.localeCompare(b, undefined, {numeric: true})
});
return arr;
};
arr = sort('name', arr);
arr2 = sort('name', arr2);
console.log(arr); // it's correct
console.log(arr2); // it's correct
arr3 = sort('value', arr3);
console.log(arr3); // it's correct
Upvotes: 3
Reputation: 37755
You need to split the alphabets and digits and then compare them
var arr = [{name: "a1", value: 1},{name: "a3", value: 1},{name: "a4", value: 1},{name: "a2", value: 1}];
var arr2 = [{name: "a1", value: 1},{name: "a3", value: 1},{name: "a14", value: 1},{name: "a12", value: 1}];
var arr3 = [{name: 1, value: 1},{name: 11, value: 1},{name: 14, value: 1},{name: 12, value: 1}];
var sort = function (prop, arr) {
prop = prop.split('.');
var len = prop.length;
arr.sort(function (a, b) {
var i = 0;
while( i < len ) {
a = a[prop[i]];
b = b[prop[i]];
i++;
}
let [key1,digit1] = (""+a).split(/(?<=[a-z])(?=\d)/)
let [key2,digit2] = (""+b).split(/(?<=[a-z])(?=\d)/)
return (key1 - key2) || (+digit1 - +digit2)
});
return arr;
};
arr = sort('name', arr);
arr2 = sort('name', arr2);
arr3 = sort('name', arr3)
console.log(arr); // it's correct
console.log(arr2); // it's not correct
console.log(arr3);
Upvotes: 1
Reputation: 1849
Name property is of type string that is why sort is performed in lexicographical order(ie alphabetical order). You would need to parse name field to sort by number inside name.
Upvotes: -1