22

I have an array of objects:

var arr = [
  {title:'50 - 50'},
  {title:'100 - 100'},
  {title:'50 - 65'},
  {title:'100 - 125'}
];

I'm attempting to sort this array so that the items appear in the following order:

var arr = [
  {title:'50 - 50'},
  {title:'50 - 65'},
  {title:'100 - 100'},
  {title:'100 - 125'}
];

Currently I'm using the following sorting function to attempt this:

arr.sort(function(a, b){
  var titleA = a.title;
  var titleB = b.title;
  var arrA = titleA.split(' - ');
  var arrB = titleB.split(' - ');
  var keyA = parseInt(arrA[0]), 
      keyB = parseInt(arrB[0]);

  // Compare the 2 keys
  if(keyA < keyB) return -1;
  if(keyA > keyB) return 1;
  return 0;
});

However, this returns the items in the following order:

var arr = [
  {title:'50 - 65'},
  {title:'50 - 50'},
  {title:'100 - 125'},
  {title:'100 - 100'}
];

It looks like I need to sort by the first number in the title and then the second number. Any ideas?

user2866434
  • 343
  • 1
  • 2
  • 6
  • use the code sample instead of code snippet when you are sharing the code. use code snippet whenever you are running it. – Prabhu Murthy Feb 17 '15 at 11:23
  • You are sorting on the first number *only*. Add another criterium for the second number when `keyA == keyB`. – Jongware Feb 17 '15 at 11:28

5 Answers5

29

Here is a cleaner and shorter version that does not require a bunch of nested if/else cases:

const sorted = arr.sort((a,b) => {

    const [a1, a2] = a.title.split(' - ').map(Number);
    const [b1, b2] = b.title.split(' - ').map(Number);

    return a1 - b1 || a2 - b2;

});
Leonid Pyrlia
  • 1,594
  • 2
  • 11
  • 14
  • 4
    By far the simplest and cleanest solution here. It works because when a and b are the same, the value is zero, which means it moves on to the next OR operand, and so on. – OXiGEN Oct 07 '20 at 04:13
19

Try this:

arr.sort(function(a, b){
  var titleA = a.title;
  var titleB = b.title;
  var arrA = titleA.split(' - ');
  var arrB = titleB.split(' - ');
  var keyA1 = parseInt(arrA[0]), keyA2 = parseInt(arrA[1]) 
      keyB1 = parseInt(arrB[0]), keyB2 = parseInt(arrB[1]);

  // Compare the 2 keys
  if (keyA1 < keyB1) return -1;
  if (keyA1 > keyB1) return 1;
  if (keyA2 < keyB2) return -1;
  if (keyA2 > keyB2) return 1;
  return 0;
});
Alex Kopachov
  • 723
  • 4
  • 9
13

In pseudocode, the logic would be the following:

Procedure: comparator(a,b)

  1. If a < b then return -1
  2. If a = b then call comparator(a1, b1) recursively, where a1 and b1 are the comparable values of the next level in the sorting.
  3. If a > b then return 1

In your concrete case, you can do simply do it by modifying your code a bit:

if (keyA < keyB) {
    return -1;
} else if (keyA > keyB) {
    return 1;
} else { // keyA == keyB
    if (titleA < titleB) {
        return -1;
    } else if (title > titleB) {
        return 1;
    } else {
        return 0;
    }
}
meskobalazs
  • 15,741
  • 2
  • 40
  • 63
  • +1 for pseudocode and the actual crux: on comparison equality, compare at next level. – dakab Apr 20 '22 at 13:59
1

Create a compare function similar to this:

arr.sort(function(a, b){
  var titleA = a.title;
  var titleB = b.title;
  var arrA = titleA.split(' - ');
  var arrB = titleB.split(' - ');
  var keyA1 = parseInt(arrA[0]), 
      keyA2 = parseInt(arrA[1]),
      keyB1 = parseInt(arrB[0]),
      keyB2 = parseInt(arrB[1]),

  // Compare the 2 keys
  if(keyA1 < keyB1) return -1;
  if(keyA1 > keyB1) return 1;
  else
  {
      if(keyA2 < keyB2) return -1;
      if(keyA2 > keyB2) return 1;
      return 0;
});
ShellNinja
  • 629
  • 8
  • 25
Mukesh Agarwal
  • 530
  • 4
  • 15
0

Another possibility is to compose a sort function based off of multiple comparator functions. Here is an example function that would do this:

function makeMultiCriteriaSort (...criteria) {
  return (a, b) => {
    for (let i = 0; i < criteria.length; i++) {
      const curCriteriaComparatorValue = criteria[i](a, b)
      // if the comparison objects are not equivalent, return the value obtained
      // in this current criteria comparison
      if (curCriteriaComparatorValue !== 0) {
        return curCriteriaComparatorValue
      }
    }
    return 0
  }
}

// sort an array with multiple criteria
arr.sort(makeMultiCriteriaSort(comparator1, comparator2))

The npm package thenby takes this idea to the next level.

Evan Siroky
  • 9,040
  • 6
  • 54
  • 73