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: .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: .jpg
IE and Firefox is work OK, the problem happens in Chrome. I guess something go wrong with the case return 0.
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/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/Usar5.jpg
IE and Firefox is work OK, the problem happens in Chrome. I guess something go wrong with the case return 0.
Share Improve this question edited Mar 2, 2018 at 4:14 vicnoob asked Mar 2, 2018 at 3:16 vicnoobvicnoob 1,18313 silver badges27 bronze badges 5- Looks the same on my end – Eddie Commented Mar 2, 2018 at 3:18
- imgur./a/4NyDq Here is my result – vicnoob Commented Mar 2, 2018 at 3:20
- @Eddie Please try in chrome – vicnoob Commented Mar 2, 2018 at 3:41
- Possible duplicate of Sorting an array of objects in Chrome – roomcayz Commented Mar 2, 2018 at 4:06
- @vicnoob: can you select an answer for this question? thanks – Carloluis Commented Mar 13, 2018 at 0:31
3 Answers
Reset to default 2The 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 bination 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 parison function). Chrome's results:
- the first sort is performed on 10 elements array (therefore, original order is preserved)
- the second sort is performed on your original array with 19 elements (in this case there is no certainty about keeping original order, and that's why the array order is changed)
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 mon 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
Javascript engines. More.
Do the following....
arr.sort(function(a,b){return (!a || !b)? 0 : (a.key - b.key) })
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 pareFunction(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.