4
\$\begingroup\$

The title sucks, but it's really very simple - given an array and a starting element, cycle between one element above, below, then two element above, and below the starting element. For example:

Start: 5
5 > 6 > 4 > 7 > 3 > 8 > 2 ... 

It doesn't matter if the code initially start with the element above or below. To complicate things a little, when you reach the end or beginning of the array, the code should continue to pick valid array elements, instead of going into invalid positions:

Start: 2
2 > 3 > 1 > 4 > 0 > 5 > 6 > 7 ...

This is the code I have. It works, but I don't really like the way to fulfil the second condition above, having that two lines repeated twice.

var distance = 0;

while ((currentHeight + this.heights[index]) < height) {
    sections.push(index);
    currentHeight += this.heights[index];

    distance = -distance + (distance >= 0 ? -1 : 1);
    index += distance;

    if (index < 0 || index >= this.heights.length) {
        distance = -distance + (distance >= 0 ? -1 : 1);
        index += distance;
    }
}

distance is the distance from the starting point, index holds the current position. The code cycles with these two lines:

distance = -distance + (distance >= 0 ? -1 : 1);
index += distance;

and it resolves the invalid array position problem by simply rerunning those two lines if it finds an invalid array position.

\$\endgroup\$
5
\$\begingroup\$

First off, your code was a bit difficult to read, because you combined the algorithm you need with your functionality, that you didn't explain. It's not only easier for people helping you, but also yourself, if you try to separate your problem from the application.

Your attempt was to calculate an index from the previous index. I instead created a function, that mapped a increasing index (0, 1, 2, 3, 4,...) to the targets (0, 1, -1, 2, -2,...). So we are looking for a function f(i) where f(0) = 0, f(1) = 1, f(2) = -1, f(3) = 2, etc.

I came up with: (i % 2 ? 1 : -1) * Math.floor( (i+1) / 2 ).

Now you just need a condition to skip new indexes outside your array. I came up with the following:

var yourArray = new Array(10);
var start = 2;

var i = 0;
var max = yourArray.length;

while (max) {
  var newI = (i%2?1:-1) * Math.floor((i+1)/2) + start;
  if (newI >= 0 && newI < yourArray.length) {
    document.write( newI + "<br>");
    // do something with yourArray[newI];
    max--;
  }
  i++;
}

My problem was how to decide when to stop the loop. For now i just loop over twice the length of the array. That will usually lead to some unnecessary iterations, but maybe someone can come up with a better solution, or there maybe a condition that comes from your application. UPDATE: Found a solution.

\$\endgroup\$
4
\$\begingroup\$

The sequence you describe is +1, -2, +3, -4, +5, -6, ... so my idea was to keep two mutating values

var step = 0;
var direction = 1;

where step is incremented and direction is negated

step++;
direction *= -1;

and are applied to the current index

index += step * direction;

each time through the loop. Otherwise, the code looks the same as RoToRa's solution (+1 for the formula, btw).

var yourArray = new Array(10);
var index = 2;

var step = 0;
var direction = 1;
var max = yourArray.length;

while (max) {
  if (index >= 0 && index < yourArray.length) {
    document.write( index + "<br>");
    // do something with yourArray[index];
    max--;
  }
  step++;
  direction *= -1;
  index += step * direction;
}
\$\endgroup\$
1
\$\begingroup\$

A much easier way of doing this is:

var myarray = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15];
var start = 8, step = 1, current = start+step;
while (myarray[current]) {
    console.log(myarray[current]);
    current = (current>start) ? start-(current-start)-1 : start+(start-current);
}

=> 10 ,7 ,11 ,6 ,12 ,5 ,13 ,4 ,14 ,3 ,15 ,2

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.