loopsiteratorsimplifytwo-way

Simplify/Neatify this two-way loop?


I've got my wires crossed somewhere (or I had not enough sleep). I need a two-way loop, and my current code is just plain ugly.

Problem: I am running along a linear datastructre using an index. I have an starting index, lets say 120. I want to run alternating into both directions.

Example: 120,121,119,122,118,123,117,...

I have a stopping criterion which needs to be met for each direction separately. If it is met for one direction, I only want to run into the other direction, if both are met I need to exit the loop. In addition I need to stop if the next index is invalid (end of data structure, say smaller than 0 or bigger than 200).

Example: Stopping execution at 116 backwards and 130 forward: 120,121,119,122,118,123,117,124,116,(break),125,126,127,128,129,130.

Running into one direction first, then the other one is unfortunately not an option.

My current code is plain ugly. It is a lot of lines without containing any "productive" code. Only iteration logic:

  int start_idx = 120;
  int forward_idx = start_idx;
  int backward_idx = start_idx;

  bool next_step_forward = true; //should next step be forward or backward?

  int cur_idx;
  while(backward_idx >= 0 || forward_idx >= 0)
  {
    if(next_step_forward   //if we should step forward
      && forward_idx >= 0) //and we still can step forward
    {
      cur_idx = ++forward_idx;

      if(forward_idx >= 200) //200 is fictive "max index"
      {
        next_step_forward = false;
        forward_idx = -1; //end of data reached, no more stepping forward
        continue;
      }

      if(backward_idx >= 0)
      {
        next_step_forward = false;
      }
    }
    else if(!next_step_forward 
            && backward_idx >= 0)
    {
      cur_idx = --backward_idx;
      if(backward_idx < 0) //beginning of data reached, no more stepping backward
      {
        next_step_forward = true;
        continue;
      }

      if(forward_idx >= 0)
      {
        next_step_forward = true;
      }
    }
    else
    {
      next_step_forward = !next_step_forward; //ever hit?, just security case
      continue; 
    }

    //loop body
    //do something with cur_idx here

    if(stoppingCriterionMet())
    {

      if(cur_idx > start_idx)
      { //this was a forward step, stop forward stepping
        forward_idx = -1;
      }
      else
      { //this was backward step, stop backward stepping
        backward_idx = -1;
      }
    }
  }

Am I missing anything? Any hints appreciated. Thanks.

Edit 1: There are lots of very nice answers, which put "do something with cur_idx" into a separate function. While this is a perfect idea for the way my question was asked, I prefer putting the iterating code somewhere else and leave the productive code there. I have a long algorithm and want to split it up after it is finished to minimize rearangement work.


Solution

  • It so happened that I coded almost this problem today. And I used a C# iterator function to do it. But I think you want a more generic solution.

    If you use a language where you can build your own iterators (C++,Java,C#), it's easy. You just make a custom iterator that initially spits out numbers starting from the center. Then you give the iterator an extra function to tell it to stop running in the current direction.

    If you're doing something like this in C (it looks C to me), you can mimic this with a struct containing the iterator state, and functions that you call to step it forward or stop it.