tags:

views:

437

answers:

7

I have a very large loop that loops a 1000 rows. I exit the loop if magic value 1 is found. If magic value 1 is not found but magic value 2 is found then the loop needs to skip to the beginning. Right now I am using a switch, some ifs and a goto. I have read that goto is not the best way. Is there a better way to make this work?

+12  A: 

To exit a loop you can use the break statement, to go onto the next record you can use the continue statement.

for(int i = 0; i < 1000; i++)
{
    if(magicValue1)
       break;
    if(magicValue2)
       continue;
}

I AM NOT CONDONING THE USE OF THE GOTO STATEMENT I AM SIMPLY POINTING OUT A POSSIBLE USE CASE

You can use goto jump statement to start/exit a loop, however I would stay away from this option unless you are using nested looping. I think the goto statement still has its uses for optimizing, exiting cleanly ect.. but in general it is best to use it quite sparingly.

for(int i = 0; i < 100; i++)
{ 
  start:

  for(int i = 0; i < 10; i++)
  {
     if(magicValue1)
       goto end;
    if(magicValue2)
       goto start;
  }
}
end :
cgreeno
-1, goto may have its uses but this isn't one them. In all cases like this you can refactor the nested loops into a separate method and use return.
Samuel
http://stackoverflow.com/questions/24451/goto-usage
cgreeno
Points 1 and 2 are not right. For 1 you could just wrap it in a try {} finally {} block and it would look much better and see my other comment for number 2.
Samuel
+1 For being able to have the ability to explain a concept without advocating its usage in all cases.
Andrew Hare
@Samuel - goto is not the big bad scary monster that everyone makes out. It is super fast and CAN BE very readable when used correctly. I do not advocate its use and have only used it once in my entire programming career.
cgreeno
@Samuel - I think it is good to have a grasp of all the elements of a language and use them when needed rather then just saying "Its bad don't use it"
cgreeno
Never said they are monsters and while they do have uses, nested loops isn't a good one. And gotos can be reable, but refactoring and sticking to SRP will produce vastly more readable code.
Samuel
@Samuel refactoring can be good thing, but it is not always an option. Saying they should not be used in a nested for statement is the wrong way to approach things. Each situation should be evaluated on its own merit.
cgreeno
In this particular case, there is nothing evil about `goto` - it is not fundamentally different to `break` and `continue` (the latter just happen to use an implicit label). If you oppose the use of `goto` in such cases, you should oppose `break` and `continue` as well.
Pavel Minaev
+10  A: 

How about this:

for(int i = 0; i < 1000; i++) {
    if(values[i] == MAGIC_VALUE_1) {
        break;
    } else if(values[i] == MAGIC_VALUE_2) {
        i = 0;
    }
}

If by "skip to the beginning" you mean "skip this record and process the next one," replace i = 0 with continue.

Can Berk Güder
was just doing that with a While loop instead
Pondidum
The only problem with this (and it will probably be a problem with the original author's wording of the problem), is that once you hit magic value 2, it will start all over until it hits magic value 2, then it will start all over, infinitely. Your code is definitely right, based on what he is saying
TheTXI
I'd actually recommend using a while loop for this, as most people expect the 3rd statement in the for loop to be the only thing that modifies the index variable. A while loop would not induce that preconception and thus be easier to grok.
rmeador
@TheTXI: Perhaps he's modifying the data, so on the next run the values are different. According to the question this answer is a valid one.
Pawel Krakowiak
@TheTXI: I think the OP must be modifying the values in the loop. Otherwise, this obviously results in an infinite loop, as you and DaveK have pointed out.
Can Berk Güder
@rmeardor: +1 for the recommendation, -1 for the use of "grok" =))
Can Berk Güder
@Pawel: I was not trying to harp on CBG at all, I upvoted him. I was just trying to add a note that based on the limited amount the OP described, it's going to hit an infinite loop. I can't fault CBG for writing the correct solution to a WTF problem.
TheTXI
@TheTXI: WTF should be a tag. =)
Can Berk Güder
Steve McConnell would be sad - You're making changes to the loop counter in the loop...
Hugoware
-1: Changing the loop counter in the middle of the loop body is really bad practice; while it's permitted by the language, it violates the principle of least surprise and is a maintenance booby trap.
Bevan
+3  A: 

A while variation with no break:

bool continue = true; int i = 0;
while (i < 1000 && continue){
    if(values[i] == MAGIC_VALUE_1) {
        continue=false;
    } else if(values[i] == MAGIC_VALUE_2) {
        i = 0;
    }
    i++;
}
Wadih M.
+1  A: 

I'm taking #2 case to mean that you want to not perform (i.e. skip) the loop body in the #2 case and not that you want to reset the loop to 0. (See the code comments if I've got that backward.)

This suggestion may be controversial because of the less conventional condition in the for loop could be said to be low on the self-documenting scale, but if that doesn't bother you, a concise way of writing what I think you you want is:

        for (int i= 0; i<values.Length && values[i]!= MAGIC_1; i++)
        {
            if (values[i] == MAGIC_2)
            {
                // Don't do the loop body for this case but continue on looping
                continue;
                // If you want to reset the loop to zero instead of skip the 2 case,
                // comment-out the continue; and un-comment the line below:
                // i=0;
            }
            // Do long loop body here
        }
JeffH
+2  A: 

I can't comment yet ( 1 rep point away)

but wouldn't this be better:

for (int i = 0; i < 1000; i++)
{
    if (magicValue1)
    {
       break;
    }
    else if (magicValue2)
    {
       dosomething();
       i=0;
    }
}

and I'm not sure by whats meant by "restart the search".

Crash893
The original post is tagged C#, so you'd want "else" instead of "Else". And your if statements need to compare the magicValues *to* something, like: if(values[i]==magicValue1)
JeffH
It was meant to be sudo code.
Crash893
Added punctuation and reformatted your code.
Bevan
+1  A: 

Just note that if you set the counter back to 0 if MagicValue is 2, and your code never changes the values, you are probably going to be in an infinite loop.

ChurchSkiz
A: 

A more complex could be:

We define 2 Extension Methods.

public static class Extensions
{
   public static bool isMagic_1(this int i)
   {
         return i == 1;
   }

   public static bool isMagic_2(this int i)
   {
         return i == 2;
   }
}

Now you can do this:

  for(int i = 0; i < 1000; i++)
  {
     if(i.isMagic_1())
       break;
     if(i.isMagic_2())
       continue;
  }

hope this helps!

MRFerocius
wouldn't it be better to return true or false
Crash893
in fact is returning true or false.
MRFerocius