4

I have found an oddity when using Array.prototype.sort() on an array of numbers and I'm not sure what's causing it.

My goal is to reverse an array using sort (not using reverse) so I can chain it like so:

const shouldReverse = Math.random() > 0.5,
      result = foo().bar().map(...).reverseIf(shouldReverse);

I believe I should be able to achieve this using sort, which seems to work in some cases but not others.

Here is a working example:

const myArray = ['a', 'b', 'c', 'd'],
      mySortedArray = myArray.sort(() => 1); 

console.log(mySortedArray);
["d", "c", "b", "a"]

And a non-working example:

const myArray = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k'],
      mySortedArray = myArray.sort(() => 1); 

console.log(mySortedArray);
["f", "k", "a", "j", "i", "h", "g", "b", "e", "d", "c"]

This only happens in Chrome and only when there are more than 10 elements in the array — could it be some form of optimisation in Chrome's V8 engine?

5
  • 3
    I think the sorting algorithm used is up to the implementation - you're not guaranteed to get bubble sort or for it to be linear from left to right (or vice versa), so returning a constant as the sorting thing, can potentially really mess with the algorithm. In short, yes, it could be "optimisation", if you take "different sorting algorithm", to mean that. Commented Sep 28, 2016 at 15:23
  • Did you see the second line on the page you linked to: "The default sort order is according to string Unicode code points."? Your question shows sorting strings but the first sentence refers to an array of numbers. If you gave it a function that compares strings it would work. Commented Sep 28, 2016 at 15:23
  • I forgot to mention it in the OP but I originally found the issue when using numbers and the issue is exactly the same when using numbers. Commented Sep 28, 2016 at 15:25
  • Actually, to answer the question that led to this, if you want to reverse using sort, then you would need sorting functions first but then you can very simply make them work the opposite way by doing a reverse = x => () => x * -1 of if you want to be more fancy reverse = (f) => function () { return f.apply(this, arguments) * -1; } Commented Sep 28, 2016 at 15:39
  • I would expect this to work if every comparison among the array items is done in their initial order. In Chrome's sort algorithm you can not even just refer to the being sorted array items within the comparison function since sometimes they even do not exist in the array. I guess FF uses a type of merge sort while Chrome is obviously doing this job totally differently. Commented Sep 28, 2016 at 16:42

1 Answer 1

3

I believe I should be able to achieve this using sort

No, you should not. You are looking for reverse.

For your specific examples, which are already sorted in ascending order, you can achieve a reversal by passing a comparison function that leads to a descending order, but this won't work for arbitrary arrays with arbitrary values.

myArray.sort((a, b) => (a<b)-(b<a));
myArray.sort(() => 1)

That's a totally inconsistent comparison function. You can't expect this to work.

This only happens in Chrome and only when there are more than 10 elements in the array

That's because the JS engine in Chrome uses a different sort algorithm for small arrays, which does its comparisons in a different order and apparently always with the higher indexed item in the second argument. You just got lucky.

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

1 Comment

I am interested in that, as well. What Bergi said is completely correct, as far as I am aware. If it is not, I would really like to know.

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.