Sebastian Weiß
Sebastian Weiß

Reputation: 359

For Loop that counts up and down from a start index inside range

I'm having trouble developing a for-loop that starts at a given integer (start) and then counts up and down from this starting point inside a given range (min to max). I want the result to be in order by distance to the given start. If a for-loop is not the right tool here, i am open for other suggestions!

Since this is hard to explain i have a example down below:

var start = 4;
var max = 10;
var min = 0;
var stepSize = 1;
for(var i=startIndex; i>=min && i<=max; ???) {
  Console.WriteLine(i)
}

The result should look like this:

4 5 3 6 2 7 1 8 0 9 10

The really tricky part for me is the end where the alternation has to stop in order to reach the max value of 10 and not go below 0 in the meantime.

I started experimenting and had a solution that would work for the first bit:

const int start = 4;
const int stepSize = 1;
    
for (var (i,j,k) = (start,1,5); Math.Abs(j)<=11; k=(k+j),j=-j-Math.Sign(j)*stepSize,i=(k+(start-5))%11) {
  Console.WriteLine(i);
}

This works fine for the first part where alternation is needed, but it breaks once the alternation needs to stop. The result from this experiment is:

4 5 3 6 2 7 1 8 0 9 -1

Upvotes: 2

Views: 876

Answers (4)

Max Play
Max Play

Reputation: 4037

Since you explicitly stated that you want a for loop that produces the pattern, how about this approach:

Find the larger "distance" first and let the loop run until this point, not starting with 0. In the loop check in both directions and do the calculations inline and call the method once beforehand with the original value.

int x = 4;
int min = 0;
int max = 10;

int largest = Math.Max(Math.Abs(min - x), Math.Abs(max - x));

YourMethod(x);
for (int i = 1; i <= largest; i++)
{
    if (x + i <= max)
        YourMethod(x + i);
    if (x - i >= min)
        YourMethod(x - i);
}

Upvotes: 2

julealgon
julealgon

Reputation: 8181

The sequence you are after:

4 5 3 6 2 7 1 8 0 9 10

Could be specified as the following:

4 - 3 - 2 - 1 - 0
- 5 - 6 - 7 - 8 - 9 10 
- - - - - - - - - - --
4 5 3 6 2 7 1 8 0 9 10

Which using something like MoreLinq, could be expressed like this:

Sequence(4, 0).Interleave(Sequence(5, 10))

Obviously, you control the start, max and min by controlling the values of both sequences. So, say you want to start from 7, going up and down towards 1 as the minimum value, and 14 as the maximum. The call would be like:

Sequence(7, 1).Interleave(Sequence(8, 14))

Lastly, this also allows you to easily change from a "up-down" to a "down-up" by swapping the intervals. Using the example above:

Sequence(8, 14).Interleave(Sequence(7, 1))

Note that Sequence also has an overload that takes a step argument, so you can additionally expand the examples below with arbitrary step increments and not only 1.

Upvotes: 2

Idle_Mind
Idle_Mind

Reputation: 39142

Here it is with a for loop, but like others have already alluded to, I think other structures are better suited for your task:

  public static void Main() {
    int start = 4;
    int max = 10;
    int min = 0;
    int stepSize = 1;
    for(int i=start, j=start; i>=min || j<=max; i-=stepSize, j+=stepSize) {
      if (i==start) {
        Console.Write(i + " ");
      }
      else {
        if (j <= max) {
          Console.Write(j + " ");
        }
        if (i >= min) {
          Console.Write(i + " ");    
        }        
      }      
    }
  }

Upvotes: 2

dumetrulo
dumetrulo

Reputation: 1991

A simple but elegant solution could generate the number sequence you want like so:

static IEnumerable<int>
UpDownCount(int start, int lower, int upper)
{
    int i = start, j = start;
    yield return start;
    while (true)
    {
        bool ilimit = ++i <= upper,
            jlimit = --j >= lower;
        if (ilimit)
            yield return i;
        if (jlimit)
            yield return j;
        if (!(ilimit || jlimit))
            yield break;
    }
}

Then you can use that sequence with LINQ or a simple foreach loop:

foreach (int i in UpDownCount(4, 0, 10))
    Console.WriteLine(i);

Upvotes: 1

Related Questions