Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Array.sort() is producing unexpected results when elements are equal?

Heyo!

I'm trying to sort an array that sometimes may be entirely equal. The function works perfectly when the array is unequal, but seems to randomly place elements when it is entirely equal. For example, I would expect the code below to print 'a,b,c...', but instead get something like: 'k, a, c, d ...'. Is this expected behavior for the sort() function? How can I produce the 'a,b,c...' functionality? Thanks!

var arrayToSort = [
  {name: 'a', strength: 1}, {name: 'b', strength: 1}, {name: 'c', strength: 1}, {name: 'd', strength: 1},
  {name: 'e', strength: 1}, {name: 'f', strength: 1}, {name: 'g', strength: 1}, {name: 'h', strength: 1},
  {name: 'i', strength: 1}, {name: 'j', strength: 1}, {name: 'k', strength: 1}, {name: 'l', strength: 1},
  {name: 'm', strength: 1}, {name: 'n', strength: 1}, {name: 'o', strength: 1}, {name: 'p', strength: 1},
  {name: 'q', strength: 1}, {name: 'r', strength: 1}, {name: 's', strength: 1}, {name: 't', strength: 1}
];

arrayToSort.sort(function (a, b) {
  return b.strength - a.strength;
});

arrayToSort.forEach(function (element) {
  console.log(element.name);
});
like image 883
Ajayc Avatar asked Dec 20 '22 09:12

Ajayc


2 Answers

The property of a sorting algorithm that leaves elements that compare as equal in their original list order is called stability. The JavaScript spec specifically allows for implementations to use unstable sort algorithms.

From the spec:

The sort is not necessarily stable (that is, elements that compare equal do not necessarily remain in their original order).

Now, how you fix your problem depends on your situation. If you know that you "like" the original order, but there's no intrinsic attributes of the objects that would give you that ordering via another sort, then a simple approach would be to make a pass through the array and add another attribute containing the original array index. You could then use that index as a secondary sort key. A final pass after the sort could remove the key (if desired).

like image 93
Pointy Avatar answered Dec 31 '22 15:12

Pointy


Based on your problem statement, you need to modify arrayToSort to take into account both strength and name

arrayToSort.sort(function (a, b) {
 if (b.strength == a.strength) {
   return a.name.localeCompare(b.name);
 } else {
   return b.strength - a.strength;
 }
});
like image 22
Dinesh Avatar answered Dec 31 '22 15:12

Dinesh