Search code examples
javascriptarrayssortingsortcomparefunction

Javascript sort by digits sum doesn't work even with compare function. Why?


I have a function that sorts an array of integers by their digits sum, in case of equal digit sum than it sort by the numbers values. This is the function:

function s(g){
    var r=0;
    while(g)r+=g%10,g/=10;
    return r;
}
function digitalSumSort(a) {
    a.sort(function(x,y){
        return s(x)!=s(y)?s(x)-s(y):x-y;
    });
    return a;
}

It sometimes works ok, but it failed at this test data:

Input: [100, 22, 4, 11, 31, 103]

Output: [100, 11, 31, 4, 22, 103]

Expected Output: [100, 11, 4, 22, 31, 103]

I couldn't figure out why it does that, and how to fix it?

Note: it is important that the code contains as least as possible characters!

Edit: This question has already been answered but I recently made the same mistake and thought of this. Is there a way to make a var act as an integer (instead of a double) when given a numeric value. I learned the trick with using floor, but sometimes I just want integer operations instead of double (with some systems they are faster, and I may have other reasons).


Solution

  • The main problem is with the s function, because it continues looping and collecting values when g is fraction.

    In addition, instead of calculating the values while sorting, you can use a Schwartzian transform aka decorate-sort-undecorate. You create an array with the computed values you'll use to sort, sort the array, than map back to the original values.

    function s(g) {
      var r = 0;
      while (g) r += g % 10, g = Math.floor(g/10); // round g down to skip redundent loops when g is a fraction
      return r;
    }
    
    function digitalSumSort(a) {
      return a
        .map(function(n) { // create an array with theorigina and the computed values
          return [s(n), n];
        })
        .sort(function(a, b) {
          return a[0] === b[0] ? a[1] - b[1] : a[0] - b[0]; // sort by the computed or original values
        })
        .map(function(n) { // get back an array of the original values
          return n[1];
        });
    }
    
    console.log(digitalSumSort([100, 22, 4, 11, 31, 103])); // [100, 11, 4, 22, 31, 103]