(Right now I'm mostly using C#. Ideas in other languages are welcome, but please translate them to C# if you can, and be explicit.)
Something I come across time and time again is a nested loop, searching through some 2D array to find an element (typically some object), which then has to be manipulated. So of course, once you find that object, you should break out of both loops so you don't needlessly continue the search for something you already found (especially in nested loops which can traversing exponentially huge arrays).
The following code is currently my preferred way of doing it:
Obj O = null;
bool KeepLooping = true;
for (int j = 0; j < height && KeepLooping; j++)
{
for (int i = 0; i < width; i++)
{
if (ObjArray[i, j] != null && ObjArray[i, j].property == search_value)
{
O = ObjArray[i, j]; // you found it, now remember it
KeepLooping = false; // clear the flag so the outer loop will break too
break;
}
}
}
Thanks to Erik Funkenbusch, it becomes much more elegant if we do this:
Obj O = null;
for (int j = 0; j < height && O == null; j++) // much, much better idea to check O for null in the outer loop
{
for (int i = 0; i < width; i++)
{
if (ObjArray[i, j] != null && ObjArray[i, j].property == search_value)
{
O = ObjArray[i, j]; // you found it, now remember it
break;
}
}
}
No more need for that pesky extra boolean!
Nevertheless, the search for alternative or better solutions goes on. Over the years I've tried many other ways, but find them not that great for one reason or another:
j
(the outer-loop iterator) to a value above height
, which will trigger it to break automatically. Not ideal because sometimes you want to remember the i
and j
values where you found it.foreach
on the 2D array. Not ideal since foreach
won't let you manipulate the collection (delete or add to it, which very typically is the reason I search for the object anyway).O
. return
effectively breaks both loops. Many times this is okay, but not always. I do this for very generic searches, but there are also quite a lot of "group searches" where I want to collectivize the traversing. In those cases, I find 2 or more objects (sometimes within the same 2D array), remember them, and only then break out of both loops.goto
? (Whoa, could this be the only legit use of a goto? It's surprisingly more readable than the KeepLooping
flag, especially if we have 3 or more loops.) Not ideal because coworkers will scream bloody murder. And in C#, will there be correct garbage cleanup after the goto
?
return;
This could get messy fast. Sometimes the object manipulation involves its own loops.There is also a very clever 7th way, thanks to User_PWY:
int size = width*height; // save this so you dont have to keep remultiplying it every iteration
for (int i = 0; i < size; i++)
{
int x = i % width; // ingenious method here
int y = i / width; // ingenious method here
O = ObjArray[x, y];
if (O != null)
break; // woohoo!
}
This effectively compacts the 2D array into one for
loop for iteration. However, some criticism has pointed out that the mod and division operators are pretty slow in comparison to just i++ or j++, so it could be slower (remember we are dealing with 2D arrays of who-knows-what size). Like i commented, there should be a way to get the division and remainder in one operation because I'm pretty sure the x86 assembly code has DIV opcodes that store the quotient and remainder in separate registers, all in one DIV instruction. But how to do/use that in C#, idk.
It would be nice if C# allowed you to name loops, such as L1
and L2
, and then do something like L1.break()
; regardless of which loop you're inside. Alas...it cannot be done in this language. (Could there be some secret way of doing this using macros?) Is there ever gonna be a C# 6.0 with this feature implemented?
Edit: in my opinion, I judge solutions on their elegance and speed. Remember we are dealing with nested loops, which can get exponentially huge. An extra operation or comparison could make a difference.
Okay, well, tell me your preferred way, especially if it's something not listed here.
goto
is a perfectly fine solution for this, Microsoft even recommends it:
The goto statement transfers the program control directly to a labeled statement.
A common use of goto is to transfer control to a specific switch-case label or the default label in a switch statement.
The goto statement is also useful to get out of deeply nested loops.
As for your question about object destruction, once you are out of scope for a scoped object the garbage collector should mark it for destruction, but I can't say for sure whether the behavior is the same if you use, for example, a using
directive around your for
loop and goto
out of it as opposed to exiting scope normally.
for (int i = 0; i < width*height; i++)
{
int x=i%width
,y=i/width;
//dostuff
}
I like this way of access to 2d array.
comment 1)
There were many comments worrying that mod(%) operator could be costly, but this is integer operation we are talking about and I think that it should make no difference other solution.
comment 2)
about the macro. I couldn't find the code but managed to produce one briefly.
#define FOR2DARRAY(WIDTH,HEIGHT)
\for (int i = 0, x = 0,y = 0; i < (WIDTH)*(HEIGHT); i++, x=i%(WIDTH),y=i/(HEIGHT))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With