0

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).

2 Answers2

1

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]
Ori Drori
  • 183,571
  • 29
  • 224
  • 209
  • Hey, thank you for the answer but I've actually already done that, the thing is, I need the code to have as few as possible characters. Your code has 50 more than the one in my solution. – Martin Dinev Nov 16 '17 at 09:46
  • Take whatever works for you. This code is longer, but it saves the need to recalculate the digits sum on each iteration. If you've got small arrays, you don't actually need it. In very large arrays you'll see a performance gain. – Ori Drori Nov 16 '17 at 09:52
  • Thank you, I'll keep that in mind. But where can I check how does `g=g/10|10` work? @Ori Drori – Martin Dinev Jul 16 '18 at 17:41
  • It's a bitwise operation that can floor positive numbers. I've replaced it with `Math.floor()`, because it doesn't work correctly with negative numbers. – Ori Drori Jul 16 '18 at 18:21
0

Thanks to @JJJ who comented "Hint: print out what s() returns (console.log(s(22)) and so on)."

I finally noticed that the function s() return incorrect values.

This code works:

function s(g){
    var r=0;
    while(g)r+=g%10,g=Math.floor(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;
}
  • 1
    If you want something as short as possible, `g=g/10|0` is the same as `g=Math.floor(g/10)` – JJJ Nov 16 '17 at 09:36
  • Thank you, any other tips? @JJJ – Martin Dinev Nov 16 '17 at 09:42
  • 1
    `|` is the bitwise OR operator and it needs to convert the number to an integer (by dropping the decimal part) before the operation. See here for details: https://stackoverflow.com/questions/7487977/using-bitwise-or-0-to-floor-a-number – JJJ Jul 16 '18 at 19:06