6

Problem

Let's make a basic list and sort it to make sure that 2 is ALWAYS first in the list. Simple enough, right?

[1, 2, 3].sort((a, b) => {
  if (a === 2) return -1;
  return 0;    
});

Chrome result: ✓

[2, 1, 3]

Node result: X

[1, 2, 3]

In order to get this behaviour in Node, you could - weirdly enough - look at the b parameter and make it return 1 if it's 2:

[1, 2, 3].sort((a, b) => {
  if (b === 2) return 1;
  return 0;    
});

With this implementation you get the opposite result; Chrome will be [1, 2, 3] and Node will be [2, 1, 3].

Questions

Do you have a logical explaination for this behaviour? Is my sorting function conceptually flawed? If so, how would you write this sorting behaviour?

9
  • 1
    My firefox Quantum also returns [1,2,3] Commented May 5, 2019 at 18:50
  • 6
    Add both if (a === 2) return -1; if (b === 2) return 1; to the compareFunction. If you add a console.log(a,b) inside the function, you should see different logs for chrome and node Commented May 5, 2019 at 18:50
  • 5
    The comparison function must correctly return 0, or a value < 0 or > 0. Your comparison incorrectly declares values equal that aren't equal, so the outcome is random for all intents and purposes. There's also no reason why a or b specifically can be expected to be 2. Commented May 5, 2019 at 18:54
  • 4
    The .sort() callback must be consistent: the result for compare(a, b) and compare(b, a) have to make sense. Commented May 5, 2019 at 18:55
  • 4

1 Answer 1

10

Do you have a logical explaination for this behaviour?

Browsers use different sorting methods. Therefore they possibly call the provided callback with different arguments in a different order. If your sort function is not consistent, the sorting won't be stable. This will lead to a wrong sort order (it also always would with different input arrays, so your sorting will never really work).

If so, how would you write this sorting behaviour?

Make sure that these two conditions apply to every possible input:

1) Two equal elements should not be sorted:

  sort(a, a) === 0

2) If the sort function gets called in inversed order, the result is also inversed:

  sort(a, b) - sort(b, a) === 0

In your case, both are not fullfilled:

  sort(2, 2) // 1 -> wrong!
  sort(2, 3) - sort(3, 2) // 1 -> wrong!

To write a stable sort, you have to look at a and b:

  function(a, b) {
    if(a === 2 && b === 2)
      return 0;
    if(a === 2)
      return 1;
    if(b === 2)
      return -1;
    return 0;
  }

Or to make that shorter:

  (a, b) => (a === 2) - (b === 2)
Sign up to request clarification or add additional context in comments.

2 Comments

I think the comparison function is called consistent, not stable
@bergi yes, that fits better.

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.