Reputation: 1183
I have an array of object like:
var arr = [{index: 1, key: undefined}, {index: 2, key: undefined},{index: 3, key: undefined},{index: 4, key: undefined},{index: 5, key: undefined},{index: 6, key: undefined},{index: 7, key: undefined},{index: 8, key: undefined},{index: 9, key: undefined},{index: 10, key: undefined},{index: 11, key: undefined},{index: 12, key: undefined},{index: 13, key: undefined},{index: 14, key: undefined},{index: 15, key: undefined},{index: 16, key: undefined},{index: 17, key: undefined},{index: 18, key: undefined},{index: 19, key: undefined} ]
I want to sort array arr by key - here is all undefined value. The return value should be the same as arr. But when i execute:
arr.sort(function(a,b){return a.key - b.key})
The result is not the same as i expected, the array order is changed. Any idea on this problem?
My result: https://i.sstatic.net/ksCQ5.jpg
Update: Tested with another array:
var b = [{index: 1, key: 10}, {index: 2, key: 10},{index: 3, key: 10},{index: 4, key: 10},{index: 5, key: 10},{index: 6, key: 10},{index: 7, key: 10},{index: 8, key: 10},{index: 9, key: 10},{index: 10, key: 10},{index: 11, key: 10},{index: 12, key: 10},{index: 13, key: 10},{index: 14, key: 10},{index: 15, key: 10},{index: 16, key: 10},{index: 17, key: 10},{index: 18, key: 10},{index: 19, key: 10} ]
Every key has same value, but when sort function is call: https://i.sstatic.net/Usar5.jpg
IE and Firefox is work OK, the problem happens in Chrome. I guess something go wrong with the case return 0.
Upvotes: 0
Views: 5966
Reputation: 4320
The problem is related with the stability of algorithms used inside array.sort
implementation which depends on the engine used to execute your javascript code.
Chrome uses Google’s V8 engine. V8's sort algorithm use a combination of insertion-sort and quick-sort. Check the actual implementation here.
Insertion-sort is used when the array is small (array.length <= 10
), otherwise quick-sort is used. The second sorting algorithm is unstable, and don't provide any guarantee about preserving order of equivalent elements.
As conclusion, I include two tests (both using your initial comparison function). Chrome's results:
const small = [
{index: 1, key: undefined},
{index: 2, key: undefined},
{index: 3, key: undefined},
{index: 4, key: undefined},
{index: 5, key: undefined},
{index: 6, key: undefined},
{index: 7, key: undefined},
{index: 8, key: undefined},
{index: 9, key: undefined},
{index: 10, key: undefined}
];
// stable sort
small.sort(function(a,b){return a.key - b.key});
console.log(small);
var arr = [
...small,
{index: 11, key: undefined},
{index: 12, key: undefined},
{index: 13, key: undefined},
{index: 14, key: undefined},
{index: 15, key: undefined},
{index: 16, key: undefined},
{index: 17, key: undefined},
{index: 18, key: undefined},
{index: 19, key: undefined}
];
// unstable sort
arr.sort(function(a,b){return a.key - b.key});
console.log(arr);
Probably you need to implement a stable sorting algorithm to ensure your code will behave the same despite the environment in which will be executed. The most common stable algorithms are bubble-sort, insertion-sort and merge-sort.
Read more about stability in sorting algorithms
Check chromium bug: V8 doesn't stable sort
Upvotes: 2
Reputation: 2564
What you are trying to do is to subtract undefined
from undefined
, and the result is NaN
.
NaN < 0
> false
NaN > 0
> false
NaN
is not -1
neither is 1
, and it is not greater nor lesser than 0, so it seems to be treated as 0
.
I'm not sure if the above sentence is true.
According to MDN:
If compareFunction(a, b) returns 0, leave a and b unchanged with respect to each other, but sorted with respect to all different elements. Note: the ECMAscript standard does not guarantee this behaviour, and thus not all browsers (e.g. Mozilla versions dating back to at least 2003) respect this.
So I've tested this in Firefox
and the order stay unchanged. But doing the same in Chrome
reproduced your problem.
Upvotes: 1
Reputation: 159
Do the following....
arr.sort(function(a,b){return (!a || !b)? 0 : (a.key - b.key) })
Upvotes: 2