tags:

views:

1034

answers:

19

Many times I need to do things TWICE in a for loop. Simply I can set up a for loop with an iterator and go through it twice.

for (i = 0; i < 2; i++)
{
 // Do stuff
}

Now I am interested in doing this as SIMPLY as I can, perhaps without an initializer or iterator ... or any really simple and elegant way ...

How would you do it?

x

+22  A: 

If its only twice, and you want to avoid a loop, just write the darn thing twice.

statement1;
statement1;  // (again)
abelenky
+1 for being blunt.
Davy8
+1 to both abelenky and Davy8, although Jordao's answer was better haha
Santiago Lezica
+1 for your second line comment
James Connell
+4  A: 

What abelenky said.

And if your { // Do stuff } is multi-line, make it a function, and call that function -- twice.

tpdi
+27  A: 

Encapsulate it in a function and call it twice.

void do_stuff() {
  // Do Stuff
}

// .....

do_stuff();
do_stuff();

Note: if you use variables or parameters of the enclosing function in the stuff logic, you can pass them as arguments to the extracted do_stuff function.

Jordão
if you inline the function, you won't even have the function call overhead
Sam Dufel
@Sam: Assuming that doesn't mess up the cache.
GMan
A: 

If what you are doing is somewhat complicated wrap it in a function and call that function twice? (This depends on how many local variables your do stuff code relies on).

You could do something like

void do_stuff(int i){
    // do stuff
}

do_stuff(0);
do_stuff(1);

But this may get extremely ugly if you are working on a whole bunch of local variables.

GWW
+1  A: 

Use function:

func();
func();

Or use macro (not recommended):

#define DO_IT_TWICE(A) A; A

DO_IT_TWICE({ x+=cos(123); func(x); })
topright
macros are evil.
Stefano Borini
Yes. And they are widely used. Even in Boost.
topright
@Pavel: Boost uses them wisely. This is not wise.
GMan
That's why it is not recommended.
topright
Then why post it in the answer? :)
GMan
One should know all possibilities. Freedom of choice is good. It is one of the first principles put in C++ design.
topright
Don't *teach* bad programming. One can know all the ways with trivial knowledge of macros, and also know not to do it. I simply fail to see the reason to say "this is awful, here you go". Just don't spread the awful.
GMan
There are many bad incomplete tutorials out there. Newcomer will read one that does not mention "avoid macroses if you can". And he will use macroses. I prefer to tell about bad programming and mention that it is bad.
topright
+2  A: 

If your compiler supports this just put the declaration inside the for statement:

for (unsigned i = 0; i < 2; ++i)
{
 // Do stuff
}

This is as elegant and efficient as it can be. Modern compilers can do loop unrolling and all that stuff, trust them. If you don't trust them, check the assembler.

And it has one little advantage to all other solutions, for everybody it just reads, "do it twice".

Jens Gustedt
It's not a question of performance, but a question of aesthetics.
dreamlax
+1 most elegant answer so far.
James
Agree with Jens, it is aesthetically please to some to have a simple for statement. When I see the for(int i=0; i<2; ++i), I immediately read "do it twice", and the i=val is a little extra info.
Les
+9  A: 

If the loop is too verbose for you, you can also define an alias for it:

#define TWICE for (int _index = 0; _index < 2; _index++)

This would result into that code:

TWICE {
    \\ Do Stuff
}

// or

TWICE
    func();

I would only recommend to use this macro if you have to do this very often, I think else the plain for-loop is more readable.

quinmars
`TWICE { TWICE ... }` oops.
jweyrich
@jweyrich: Since both variable declarations are in different scopes, the second _index should shadow the first one and hence it should work. But to be honest I haven't tried it out.
quinmars
or #define TWICE(index) ( for (index = 0; index < 2; index++) ) then call with TWICE(i) { ... }
alesplin
A: 

jump instruction is pretty slow,so if you write the lines one after the other,it would work faster,than writing a loop. but modern compilers are very,very smart and the optimizations are great (if they are allowed,of course). if you have turned on your compiler's optimizations,you don't care the way,you write it - with loop or not (:

EDIT : http://en.wikipedia.org/wiki/compiler_optimizations just take a look (:

Kiril Kirov
+1  A: 

Good rule: three or more, do a for.

I think I read that in Code Complete, but I could be wrong. So in your case you don't need a for loop.

JimDaniel
A: 
//dostuff
  stuff;
//dostuff (Attention I am doing the same stuff for the :**2nd** time)
  stuff;
Ahmed
I think the comments are a bit much..
Brendan Long
+32  A: 

This is elegant because it looks like a triangle; and triangles are elegant.

i = 0; 
here: dostuff(); 
i++; if ( i == 1 ) goto here;
Ilan
Upvote for chutzpah.
Ladlestein
+1 for mocking the ambiguity of OP's requirement in a way that made me laugh
R..
Personally, I find only isosceles and equilateral triangles to be elegant.
dreamlax
-1 for the goto, but I agree with 'R', so net 0.
Les
+1 but your last statement ends with a colon instead of a semicolon. Fix the typo.
Chris Lutz
@Les: I think goto here is part of the mocking.
himself
+1 - I just cant stop laughing.
Praveen S
-1: This is funny but really should not be the top answer to the question.
Zan Lynx
This is the worst method ever
Ahmed
A: 

First, use a comment

/* Do the following stuff twice */

then,
1) use the for loop
2) write the statement twice, or
3) write a function and call the function twice
do not use macros, as earlier stated, macros are evil.

(My answer's almost a triangle)

Les
It seems like the comment would just add noise. If someone can't tell that you're doing something twice from the code, you're either doing it wrong or they shouldn't be looking at your code.
Brendan Long
Many believe in self documenting code, I came up in the school of commenting code (or as I like to call it "self verifying code"). I find comments to be like redundancy in hardware, it costs more but real intentions (inspite of the implementation) are more obvious. Yes, comments can go out of date because others don't keep them up to date, nothing's perfect. Comments are probably a SO discussion in and of itself.
Les
A: 
void loopTwice (bool first = true)
{
    // Recursion is your friend
    if (first) {loopTwice(false);}

    // Do Stuff
    ...
}

I'm sure there's a more elegant way, but this is simple to read, and pretty simply to write. There might even be a way to eliminate the bool parameter, but this is what I came up with in 20 seconds.

Chris Case
This isn't simple to read. `loopTwice(false)` actually means "do once".
dreamlax
So, perhaps: void loopTwice (bool second = false){ if (!second) { loopTwice(true); } // Do Stuff}
Chris Case
A: 

Many people suggest writing out the code twice, which is fine if the code is short. There is, however, a size of code block which would be awkward to copy but is not large enough to merit its own function (especially if that function would need an excessive number of parameters). My own normal idiom to run a loop 'n' times is

  i = number_of_reps;
  do
  {
    ... whatever
  } while(--i);

In some measure because I'm frequently coding for an embedded system where the up-counting loop is often inefficient enough to matter, and in some measure because it's easy to see the number of repetitions. Running things twice is a bit awkward because the most efficient coding on my target system

  bit rep_flag;

  rep_flag = 0;
  do
  {
    ...
  } while(rep_flag ^= 1); /* Note: if loop runs to completion, leaves rep_flag clear */

doesn't read terribly well. Using a numeric counter suggests the number of reps can be varied arbitrarily, which in many instances won't be the case. Still, a numeric counter is probably the best bet.

supercat
If you know the number of repetitions, just use a `for` loop. `do..while` suggests the idea of indefinitely/continuously repeating a task until a condition is met. Used like this, it offers no significant advantage over a for loop except that the number of repetitions and the loop decrementer have suddenly been separated by a body of code.
dreamlax
@dreamlax: My counting idiom is most typically used on loops which are five lines or less, and the most common reason for me to say "i=16;" immediately before a "do" statement will be for a counting-down-to-zero loop. It may not be the most common idiom, but I find it's nicer to be consistent in that pattern than to use for() loops in places where speed and code space don't matter and use the do-while() when they do, especially since (in small-micro development) it's often not possible to tell in advance whether code space is going to matter.
supercat
@dreamlax: BTW, when developing for the PC, or for embedded compilers that recognize the normal loop idiom and can optimize for it (e.g. the TMS 32050 compiler will use the hardware loop facility) I generally use the 'normal' for loop; I mainly avoid it on platforms where it often poses a meaningful efficiency difference. If I have an inner loop where counting up would increase execution time 50% or more (it happens), it seems cleaner to have an outer loop use the same pattern than to use 'for' for one and 'do-while' for the other. YMMV.
supercat
What, you would miss a perfect opportunity to use `while (i --> 0)` ?!
Porculus
@supercat: Consider an example where the loop counter is incremented/decremented by a value other than 1. With a `do..while` loop, you may know the initial value of the counter but will not know how it is affected with each iteration until you have reached the end of the loop body. With a `for` loop, you can immediately see all of the information pertaining to how the loop will execute. In my opinion, a `for` loop should always be used if the number of iterations can be determined prior to entering the loop. [...]
dreamlax
[...] If the compiler cannot figure out the most efficient way to loop for the target architecture, chances are you end up writing it in assembly anyway.
dreamlax
+1  A: 

What about this??

void DostuffFunction(){}

for (unsigned i = 0; i < 2; ++i, DostuffFunction());

Regards, Pablo.

pcazallas
+4  A: 

Unfortunately, this is not for C, but for C++ only, but does exactly what you want:

Just include the header, and you can write something like this:

10 times {
  // Do stuff
}

I'll try to rewrite it for C as well.

phimuemue
I want to +1 for brilliantly useful and readable abuse of the language, but I don't think this will work for C. :(
Chris Lutz
Thanks, I think it get's quite complicated in pure C...
phimuemue
A: 

What is elegance? How do you measure it? Is someone paying you to be elegant? If so how do they determine the dollar-to-elegance conversion?

When I ask myself, "how should this be written," I consider the priorities of the person paying me. If I'm being paid to write fast code, control-c, control-v, done. If I'm being paid to write code fast, well.. same thing. If I'm being paid to write code that occupies the smallest amount of space on the screen, I short the stock of my employer.

Crashworks
A: 

Assuming C++0x lambda support:

template <typename T> void twice(T t)
{
    t();
    t();
}

twice([](){ /*insert code here*/ });

Or:

twice([]()
{ 
    /*insert code here*/ 
});

Which doesn't help you since you wanted it for C.

MSN
A: 

Close to your example, elegant and efficient:

for (i = 2; i; --i)
{
    /* Do stuff */
}

Here's why I'd recommend that approach:

  • It initializes the iterator to the number of iterations, which makes intuitive sense.
  • It uses decrement over increment so that the loop test expression is a comparison to zero (the "i;" can be interpreted as "is i true?" which in C means "is i non-zero"), which may optimize better on certain architectures.
  • It uses pre-decrement as opposed to post-decrement in the counting expression for the same reason (may optimize better).
  • It uses a for loop instead of do/while or goto or XOR or switch or macro or any other trick approach because readability and maintainability are more elegant and important than clever hacks.
  • It doesn't require you to duplicate the code for "Do stuff" so that you can avoid a loop. Duplicated code is an abomination and a maintenance nightmare.

If "Do stuff" is lengthy, move it into a function and give the compiler permission to inline it if beneficial. Then call the function from within the for loop.

Andrew Cottrell