0

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/

9
  • How should it be sorted compared to how it is currently? Commented Nov 16, 2017 at 18:38
  • @zfrisch See live demo please. It should be sorted in order with resulting list ordered first by ID then by Name Commented Nov 16, 2017 at 18:41
  • I'm asking because it wasn't clear to me from the demo. Both the IDs and the Names are the same? Regardless for perpetuity it should be outlined within your question not externally. Commented Nov 16, 2017 at 18:59
  • @zfrisch please see updated demo, I updated the initial list Commented Nov 16, 2017 at 19:04
  • Can you post more of your code here? Some of the array of objects, etc? Posting code here shouldn't need to go elsewhere to answer. Commented Nov 16, 2017 at 19:05

2 Answers 2

1

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

Sign up to request clarification or add additional context in comments.

6 Comments

I know about the options of using `{numeric: true}' but I haven't seen and can't find documentation on the undefined part. Can you explain what that does exactly or point me in the right direction? I do know it's important as it's a make-or-break deal for the code to work.
In addition to @Matt 's question, does localeCompare automatically convert to lowercase when comparing?
@user8571142 It does not do the convert from upper to lower.
Thanks, so if I want to compare only lowercase then I have to set them to lowercase first
@HassanImam can you also explain the use of undefined here?
|
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.