Daniel Daniel - 4 months ago 12
Javascript Question

Difference between two numbers in looping numerical sequence

I want to find the shortest distance between two numbers in looping sequence, e.g. 0 to 6:

... 0 1 2 3 4 5 6 0 1 2 3 4 5 6 0 1 2 3 4 5 6 ...


In also need to know which "way" is shorter (to the left or to the right).

So, if my two numbers are 0 and 6, the shortest distance is 1 by counting backwards (to the left).

The following function works, but only if
next
is greater than
crt
.

var MAX_NUMBER = 6; // 0 1 2 3 4 5 6 0 1 2 3 4 5 6 0 1 2 3 4 5 6

function shorterDirection(crt, next) {
var toRight = next - crt;
var toLeft = MAX_NUMBER - (next - crt - 1);

return toLeft < toRight ? 'left' : 'right';
}

console.log(shorterDirection(0, 6));


I can't figure out how to make it work both ways. For example, if I use
shorterDirection(4, 3)
, I want the function to return
left
.

Answer

You could use this:

function shorterDirection(crt, next) {
  var toRight = (next + MAX_NUMBER+1 - crt) % (MAX_NUMBER+1);
  return toRight > (MAX_NUMBER+1) / 2 ? 'left' : 'right';
}

Note that there can be ties. In that case the above will return left, even though right would be just as good.

As you can see there is a lot of MAX_NUMBER+1 in there. It would be more suitable if you would have a constant NUMBER_COUNT, which would be one greater than the MAX_NUMBER you have now.

How it works

You would start by writing this:

var toRight = next - crt;

But that goes "wrong" when next is less than crt -- you get a negative number. To solve that you would add MAX_NUMBER+1:

var toRight = next + NUMBER+1 - crt;

... but now you get a too large number when next is greater than crt. That you can solve by subtracting as many NUMBER+1 as necessary to get within the range 0...MAX_NUMBER. That is what the modulo (%) operator does. So you get:

var toRight = (next + MAX_NUMBER+1 - crt) % (MAX_NUMBER+1);

Once you have that result, you can reason that if it takes more than half of the numbers to go to the right, you better go to the left (which will be less than half of the numbers). This is encoded as:

return toRight > (MAX_NUMBER+1) / 2 ? 'left' : 'right';