Reputation: 1322
I'm writing a graphics program in C# and I couldn't figure out a good way to run a for loop between two values, where either one may be larger or smaller than the other.
To demonstrate, the following code works perfectly when X2>X1:
for (int x = X1; x<=X2; x++) {
//code
}
However, it fails when X2<X1. What I want to happen in this situation is that the loop starts at X1 and goes backwards until X2.
I since I'm doing a graphics program, I can't simply swap X1 and X2 when X2<X1, as this would mean swapping their associated Y values, which could produce the same problem just for Y values. The loop must always start at X1, it's the direction(+/-) that needs to change, not the order of values.
I've thought of a few solutions however they all have flaws, it's worth noting that X1 will never equal X2.
#1: Replicate loop
if (X2<X1) {
for (int x = X1; x>=X2; x--) {/*code*/}
} else {
for (int x = X1; x<=X2; x++) {/*code*/}
}
Unsuitable because of replicated code, especially if the "//code" section is particularly long
#2: Lots of ternaries
for (int x = X1; x!=X2+(X2<X1?-1:1); x+=(X2<X1?-1:1)) {/*code*/}
While this code works and is concise, it's readability is terrible. Also I've seen in various places that using "not equal to" for your loop constraint is bad practice source
#3: Use a while loop
int x = X1;
while(true) {
//code
if (X2<X1) {
x--;
if (x<X2) break;
} else {
x++;
if (x>X2) break;
}
}
This solution seems very long and convoluted to perform such a simple task, in addition, use of "while(true)" is also bad practice source
Upvotes: 0
Views: 3431
Reputation: 43
Why so complicated?
for (int n = 0; n < Count; n++)
{
int Index = (ascending ? n : Count - 1- n);
}
Upvotes: -1
Reputation: 82504
A simple solution would be to use one variable for the loop itself, and another variable for the steps:
int length = Math.Abs(x1-x2);
for(int i=0; i <= length; i++)
{
// step will go either from x1 to x2 or from x2 to x1.
int step = (x1 < x2) ? x1 + i : x2 + (length-i);
}
Of course, you can wrap the entire loop in a method, so you wouldn't have to repeat the code:
void ForLoopUnknownDirection(int start, int stop, Action<int> action)
{
int length = Math.Abs(start-stop);
for(int i=0; i <= length; i++)
{
int step = (start < stop) ? start + i : stop + (length-i);
action(step);
}
}
This way you can do whatever you want between the numbers while only writing the loop code once.
Upvotes: 2
Reputation: 546
Use a directional increment ( d in the code below )
var d = (x1 > x2) ? -1 : 1;
var i = x1;
while (i != x2)
{
//
// insert your code here
//
i = i + d;
}
Am I purdy? 😜
Upvotes: 0
Reputation: 1631
Maybe extract a method like this
private static IEnumerable<int> Step(int start, int end)
{
if (start < end)
{
for (int x = start; x <= end; x++)
yield return x;
}
else
{
for (int x = start; x >= end; x--)
yield return x;
}
}
Then you can do
foreach (int x in Step(X1, X2))
{
/*code*/
}
Upvotes: 1
Reputation: 23088
I think the most readable option is to simple create/extract method from the repeating code (the first proposed version):
void ComputeRenderedStuff(int x)
{
// do your computations for x
}
if (X2<X1)
for (int x = X1; x>=X2; x--)
ComputeRenderedStuff(x);
else
for (int x = X1; x<=X2; x++)
ComputeRenderedStuff(x);
Upvotes: 3
Reputation: 35430
Simply use Math.Min()
and Math.Max()
to choose lower and upper boundaries.
Something like this:
int MinX = Math.Min(X1, X2);
int MaxX = Math.Max(X1, X2);
for (int x = MinX; x <= MaxX; x++) {
//code
}
Upvotes: 1