John B
John B

Reputation: 71

for-loop to cover range increasing/decreasing based on sign of step

How would I modify this for-loop so that it counts up for positive values of Step, but counts down for negative values of Step?

For Step = 2, the expected output is 2 4 6 8 10

For Step =- 2, the expected output is 10 8 6 4 2

// assume these 3 come from user input
int Lower = 2;
int Upper = 10;
int Step = 2;

for ( int i = Lower; i <= Upper; i += Step )
{
    Console.Write(i + " ");
}

Upvotes: 3

Views: 913

Answers (6)

hemantsharma
hemantsharma

Reputation: 535

for(int i=Step>0?Lower:Upper; Step>0? i<=Upper: i>= Lower; i+=Step)
{
    Console.Write(i + " ");
}

@john All you need to update the looping conditions.

Upvotes: 0

Wai Ha Lee
Wai Ha Lee

Reputation: 8805

Just obey the KISS principle.

You can just put the logic into the initialiser and the condition of the for statement:

public static void ForLoopWithDirectionBasedOnStep(int minValue, int maxValue, int step)
{
    // Avoid obvious hang
    if ( step == 0 )
        throw new ArgumentException("step cannot be zero");

    //  ( initialiser                           ; condition                     ; iterator  )
    for ( int i = step > 0 ? minValue : maxValue; minValue <= i && i <= maxValue; i += step )
        Console.Write(i + " ");
}

so:

  • ForLoopWithDirectionBasedOnStep(minValue: 2, maxValue: 10, step: 2) returns:

    2 4 6 8 10
    
  • ForLoopWithDirectionBasedOnStep(minValue: 2, maxValue: 10, step: -2) returns:

    10 8 6 4 2
    

as desired.


The initialiser sets the start value

int i = step > 0 ? minValue : maxValue;

by using the conditional operator and is equivalent to

int i;
if ( step > 0 )
    i = minValue;
else
    i = maxValue;

The condition

minValue <= i && i <= maxValue

simply checks that the loop variable is within the range [minValue, maxValue].


Note that bad inputs are handled automatically because (emphasis mine):

The condition section, if present, must be a boolean expression. That expression is evaluated before every loop iteration.

so something like ForLoopWithDirectionBasedOnStep(minValue: 10, maxValue: 0, step: -2) which would count down from 0 to 10 doesn't print anything because, since 0 < 10, the body of the for statement is never executed.

Upvotes: 3

Dave
Dave

Reputation: 2200

You can do two for loops based on the sign of the step variable:

static void Main(string[] args)
    {
      int lower = 2;
      int upper = 10;
      int step = -2;

      if (Math.Sign(step) == 1)
      {
        for (int i = step; i < upper; i += step)
        {
          Console.WriteLine(string.Format("{0}", i));
        }
      }
      else if (Math.Sign(step) == -1)
      {
        for (int i = upper; i >= lower; i += step)
        {
          Console.WriteLine(string.Format("{0}", i));
        }
      }
      Console.ReadLine();
    }
  }

Upvotes: 1

Sayse
Sayse

Reputation: 43320

You need a pre-processing step to change the comparison in the for loop as well as its limits

int Lower = 2;
int Upper = 10;
int Step = -2;
Func<int, bool> comparator = (j) => j <= Upper;


if (Step < 0)
{
    var temp = Lower;
    Lower = Upper;
    Upper = temp;
    comparator = (j) => j >= Upper;
}


for(int i=Lower; comparator(i); i+=Step)
{
    Console.Write(i + " ");
}

DotNetFiddle

Upvotes: 2

Kunal Mukherjee
Kunal Mukherjee

Reputation: 5853

You can make a Func delegate to check if the step is negative and invert the bound checking condition.

Here's a sample:


class Program
{
    public static void Print(int Lower, int Upper, int Step)
    {
        Func<int, bool> checkBounds = (i) => i <= Upper;

        if (Step < 0)
        {
            Swap(ref Lower, ref Upper);
            checkBounds = (i) => i >= Upper;
        }

        for (int i = Lower; checkBounds(i); i += Step)
            Console.Write($"{i} ");
    }

    public static void Swap<T>(ref T a, ref T b)
    {
        T temp = a;
        a = b;
        b = temp;
    }

    static void Main(string[] args)
    {
        // assume these 3 come from user input
        int Lower = 2;
        int Upper = 10;
        int Step = -2;

        Print(Lower, Upper, Step);
    }
}

Upvotes: 0

schgab
schgab

Reputation: 666

Note that this code is untested but the idea is to use a Predicate<T> for the loop and switching Upper and Lower if step is negative

// assume these 3 come from user input
int Lower = 2;
int Upper = 10;
int Step = 2;
if(step < 0){ int temp = Lower; Lower = Upper; Upper = temp;}
Predicate<int> LoopPred = (i =>
{
  if(Step < 0)
    return i >= Upper;
  return i <= Upper;
})


for(int i=Lower; LoopPred(i); i+=Step)
{
    Console.Write(i + “ “);
}

Upvotes: 0

Related Questions