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?

Vinnie James
  • 5,763
  • 6
  • 43
  • 52
  • 1
    Possible duplicate of [Array.sort Sorting Stability in Different Browsers](http://stackoverflow.com/questions/3026281/array-sort-sorting-stability-in-different-browsers) – Josh Lee Mar 24 '17 at 17:18
  • You may want to check out [Tinysort](http://tinysort.sjeiti.com/), it can multiple-sort : `tinysort(array,'value','thing')` – Jeremy Thille Mar 24 '17 at 17:20

3 Answers3

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;
          }
        }
      }
    }
  };
Brian Glaz
  • 15,468
  • 4
  • 37
  • 55
2

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'));
Nina Scholz
  • 376,160
  • 25
  • 347
  • 392
  • Did you mean `b[key]` instead of `b.key`? – user2357112 Mar 24 '17 at 20:00
  • I like the simplicity of this! – Vinnie James Mar 27 '17 at 16:40
  • I just stumbled across this. Maybe interesting to mention: The linked page [Array#sort](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/sort) now shows that sort is stable for all browsers except IE for several versions.. – prohit Jun 17 '20 at 11:03
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.

Community
  • 1
  • 1
glass duo
  • 404
  • 5
  • 16