Reputation: 91
I want to sort an array of objects by both id and name. First it should be sorted by id in ascending order. Then it should be sorted by name in ascending order.
Sort function
<script>
$(document).ready(function() {
var list = [{
"id": "ts1",
"name": "TS1"
}, {
"id": "ts10",
"name": "TS10"
}, {
"id": "ts11",
"name": "TS11"
}, {
"id": "ts12",
"name": "TS12"
}, {
"id": "ts13",
"name": "TS2"
}, {
"id": "ts13",
"name": "TS1"
}, {
"id": "ts13",
"name": "TS3"
}, {
"id": "ts14",
"name": "TS14"
}, {
"id": "ts15",
"name": "TS15"
}, {
"id": "ts16",
"name": "TS16"
}, {
"id": "ts17",
"name": "TS17"
}, {
"id": "ts18",
"name": "TS18"
}, {
"id": "ts19",
"name": "TS19"
}, {
"id": "ts2",
"name": "TS2"
}, {
"id": "ts20",
"name": "TS20"
}, {
"id": "ts21",
"name": "TS21"
}, {
"id": "ts22",
"name": "TS22"
}, {
"id": "ts3",
"name": "TS3"
}, {
"id": "ts4",
"name": "TS4"
}, {
"id": "ts5",
"name": "TS5"
}, {
"id": "ts6",
"name": "TS6"
}, {
"id": "ts7",
"name": "TS7"
}]
list.sort(Sort_ID_Name);
console.log(list);
});
function Sort_ID_Name(a, b) {
try {
var aID = a.id.toLowerCase();
var bID = b.id.toLowerCase();
var aName = a.name.toLowerCase();
var bName = b.name.toLowerCase();
return ((aID < bID) ? -1 : ((aID > bID) ? 1 : ((aName < bName) ? -1 : ((aName > bName) ? 1 : 0))));
} catch (err) {}
}
</script>
Currently the sorted list shows up like this:
{id: "ts1", name: "TS1"}
{id: "ts10", name: "TS10"}
{id: "ts11", name: "TS11"}
{id: "ts12", name: "TS12"}
{id: "ts13", name: "TS1"}
{id: "ts13", name: "TS2"}
{id: "ts13", name: "TS3"}
{id: "ts14", name: "TS14"}
{id: "ts15", name: "TS15"}
{id: "ts16", name: "TS16"}
....
The ideal state is like this
{id: "ts1", name: "TS1"}
{id: "ts2", name: "TS2"}
...
{id: "ts10", name: "TS10"}
{id: "ts11", name: "TS11"}
{id: "ts12", name: "TS12"}
{id: "ts13", name: "TS1"}
{id: "ts13", name: "TS2"}
{id: "ts13", name: "TS3"}
{id: "ts14", name: "TS14"}
{id: "ts15", name: "TS15"}
{id: "ts16", name: "TS16"}
....
The function works only when the list is very short, but when the list is long it doesn't work well. See live demo- https://jsfiddle.net/0xLd6sms/2/
Upvotes: 0
Views: 162
Reputation: 21926
You're doing >/<
comparisons with strings. Those work on unicode point values, which is rarely what you want. Change this:
var aID = a.id.toLowerCase();
var bID = b.id.toLowerCase();
var aName = a.name.toLowerCase();
var bName = b.name.toLowerCase();
To this:
var reg = /\d+/; // matches 1 or more number characters
var aID = +a.id.match(reg)[0]; // unary + coerces to number
var bID = +b.id.match(reg)[0];
var aName = +a.name.match(reg)[0];
var bName = +b.name.match(reg)[0];
Now you're comparisons will be on the actual number values in the strings.
Upvotes: 0
Reputation: 22534
You can use custom sort method using localeComapre()
specifying the numeric: true
option, it will smartly recognize numbers
var list = [{ "id": "ts1", "name": "TS1" }, { "id": "ts10", "name": "TS10" }, { "id": "ts11", "name": "TS11" }, { "id": "ts12", "name": "TS13" }, { "id": "ts13", "name": "TS2" }, { "id": "ts13", "name": "TS1" }, { "id": "ts13", "name": "TS3" }, { "id":"ts14", "name": "TS14" }, { "id": "ts15", "name": "TS15" }, { "id": "ts16", "name": "TS16" }, { "id": "ts17", "name": "TS17" }, { "id": "ts18", "name": "TS18" }, { "id": "ts19", "name": "TS19" }, { "id": "ts2", "name": "TS2" }, { "id": "ts20", "name":"TS20" }, { "id": "ts21", "name": "TS21" }, { "id": "ts22", "name": "TS22" }, { "id": "ts3", "name": "TS3" }, { "id": "ts4", "name": "TS4" }, { "id": "ts5", "name": "TS5" }, { "id": "ts6", "name": "TS6" }, { "id": "ts7", "name": "TS7" }];
list.sort((a,b) => a.id.localeCompare(b.id, undefined, {numeric: true}) || a.name.localeCompare(b.name, undefined, {numeric: true}));
console.log(list);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Upvotes: 1