1

How can I ensure a stable .sort() order across all browsers? JavaScript

I have an array of objects, eg

[{
 thing: 'walker',
 value: 1
},
{
 thing: 'texas',
 value: 2
},
{
 thing: 'ranger',
 value: 2
}]

When sorting the array I sort them alternating asc/desc using:

 _sortNumber (key, dir) {
    return function(a, b) {
      if (dir) {
        // sort descending
        return b[key] - a[key];
      }
      else {
        // sort ascending
        return a[key] - b[key];
      }
    }
  };

array.sort(this._sortNumber('value', Boolean));

However, the order of texas and ranger seem to randomly change. I believe due to the fact that they are the same number, however, I would like it to be consistent.

How can I ensure consistency; or sort on a secondary value (eg thing alphabetically), in order to ensure I always get the same sort result?

2

4 Answers 4

3

First of all, like Array#sort and other sort implementations:

The sort is not necessarily stable.

To maintain a stable sort, you could use a unique value, like an index as last sort value in the chain of sorting criteria, like

function asc(key) {
    return function (a, b) {
        return a[key] - b[key] || a.id - b.id;
    };
}

array.sort(asc('value'));
Sign up to request clarification or add additional context in comments.

3 Comments

Did you mean b[key] instead of b.key?
I like the simplicity of this!
I just stumbled across this. Maybe interesting to mention: The linked page Array#sort now shows that sort is stable for all browsers except IE for several versions..
3

Since you are writing your own sorting function anyway, you can just define what the logic should be when the values are equal.

_sortNumber (key, dir) {
    return function(a, b) {
      if (dir) {
        // sort descending
        if( a[key] !== b[key])
        {
          return b[key] - a[key];
        } else { //They are same.. sort by something else
          if (a.thing < b.thing){
            return 1;
          }else if (a.thing > b.thing){
            return  -1;
          }else{
            return 0;
          }
      }
      else {
        // sort ascending
        if( a[key] !== b[key])
        {
          return a[key] - b[key];
        } else {
          if (a.thing < b.thing){
            return -1;
          }else if (a.thing > b.thing){
            return  1;
          }else{
            return 0;
          }
        }
      }
    }
  };

3 Comments

The thing values are strings, so subtracting them doesn't make sense.
That's still not returning the positive/negative/zero indicators it's supposed to return.
There is localeCompare for that.
1

You need to sort not only by value but also by thing

see this post: How to sort an array of objects by multiple fields?

If you use Excel and you've ever set the criteria for sort, you've seen how they give you the first, second, third, etc, fields to sort by. That's what you need to do. Set the first field as value and the second field as thing

The post I shared gives the code to do that.

Comments

0

I think it's worth adding an updated answer to this rather old question as it ranks well with search engines.

In 2025, you can expect all supported browsers to use a stable sort for Array.prototype.sort. See MDN:

Since version 10 (or ECMAScript 2019), the specification dictates that Array.prototype.sort is stable.

According to caniuse, all major browsers have supported a guaranteed stable sort since early 2020.

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.