tags:

views:

364

answers:

11
if (x() > 10)
{
    if (y > 5)
        action1(p1, p2, p3, p4);
    else
        action2(p1, p2);
}
else
{
    if (z > 2)
        action1(p1, p2, p3, p4);
    else
        action2(p1, p2);
}

I real project on mine, action1 and action2 are actually 2-3 lines of code and those functions that are invoked take 6-8 parameters in total, so writing them as a single function doesn't seem right.

UPDATE: I forgot to mention this, and now I see many answers just don't work. x() is expensive operation and has side-effects, so it should not be called twice.

+10  A: 

You could always do:

if ((x > 10) ? (y >5) : (z > 2)) action1
else action2

For completeness sake, any if p then q else r statement can be expressed logically as (!p && r) || q. So, we can express the original statement as:

a = x > 10
b = y > 5
c = z > 2
(!a && (!c && action2) || ((!b && action2) || action1))

Which you can expand out as:

(!a && !c && action2) || 
(!a &&  c && action1) || 
( a && !b && action2) || 
( a &&  b && action1)

If you collect action1 to one side, you get:

( a &&  b && action1) ||
(!a &&  c && action1) || 

( a && !b && action2) || 
(!a && !c && action2)

It really expands to:

( a &&  b &&  c && action1) ||
( a &&  b && !c && action1) ||
(!a &&  b &&  c && action1) || 
(!a && !b &&  c && action1) || 

( a && !b &&  c && action2) || 
( a && !b && !c && action2) || 
(!a &&  b && !c && action2) ||
(!a && !b && !c && action2)

And from that we can see we can simplify it to:

( a &&  b &&  c && action1) ||
( a &&  b && !c && action1) ||
(!a &&  b &&  c && action1) || 
(!a && !b &&  c && action1) || 
action2

Since all paths leading to action2 are the negation of any path leading to action1, and we can further reduce it to:

( a &&  b && action1) ||
(!a &&  c && action1) || 
action2

Which can itself be reduced to:

((( a &&  b &&) || (!a &&  c)) && action1) || 
action2

Which can then be written as:

if ((a && b) || (!a && c)) action1
else action2

Which becomes: if ((x > 10 && y > 5) || (!(x > 10) && z > 2)) action1 else action2

Which is what we get anyways.

MSN
This kind of situation comes up a LOT. Two points to keep in mind: 1) readability trumps minor efficiency gains, and 2) become familiar with Boolean logic and the optimizations you can perform.
dwc
Paul Tomblin
This isn't quite right. If x>10 and y<=5, but z>2, this will perform action1 when it should perform action 2.
gnovice
that's wrong! if x>10, y<5, z>2 , action2 should be executed, and not action1
Igor Oks
I edited it so it works in all cases
jpalecek
The edit looks right now.
gnovice
Whee, thanks! I was busy trying to expand this out logically so I missed the last 5 minutes :)
MSN
LOL! FAIL the "simplify" test!
le dorfier
At least you provided an ample demonstration of why simplifying isn't a good idea.
Paul Tomblin
Yes, well, at least I also showed how to actually derive it. :/
MSN
+5  A: 

I like the original, verbose version. But only if it follows the inside logic of the system that the code is describing. Otherwise, maybe it should be the "opposite":

int xRes = x();
if (y > 5) 
{
    if (xRes > 10)
        action1(p1, p2, p3, p4);
    else
        action2(p1, p2);
}
else if (z > 2)
{
    if (xRes > 10)
        action1(p1, p2, p3, p4);
    else
        action2(p1, p2);
}
else
{
    action2(p1, p2);
}

Anyway, if you are interested in the shortest solution, this can be it:

((x>10 && y>5) || (x<=10 && z>2)) ? action1(p1, p2, p3, p4) : action2(p1, p2);
Igor Oks
It should be "int xRes = x();", not bool. Later you compare it to 10, so...
Daniel Daranas
@Daniel: Sure, thanks.
Igor Oks
+12  A: 
if ((x > 10 && y > 5) || (x <= 10 && z > 2))
   action1(p1, p2, p3, p4);
else
   action2(p1, p2);
Coltin
Err...fixing endlines hold on
Coltin
Darn, beat me to it! =)
gnovice
it's the clearest, without "tricks" to beat the most booleans out of it. go for clearity. and this does, so i give +1
Johannes Schaub - litb
+15  A: 
if (should_do_action1(x(), y, z))
    action1(p1, p2, p3, p4);
else
    action2(p1, p2);
Roger Lipscombe
This is also a good option, and I like its genericity.
Daniel Daranas
+1  A: 

If you want to do it with just 1 if statements, I think it would be:

if ((x > 10) && (y > 5)) || ((x <= 10) && (z > 2))
    action1(p1, p2, p3, p4);
else
    action2(p1, p2);
gnovice
+2  A: 
//Yeah, I know this is wrong. Explanation below.
if ((x() > 10 && y > 5) || (x() <= 10 && z > 2))
    action1(p1, p2, p3, p4);
else
    action2(p1, p2);

[edit] Changed code because my conditional logic was wrong.

But personally, for readability's sake I prefer your more verbose version.

[edit2] As the comments have noticed, I seem to be having trouble getting this exactly right. I would note that this is because the way I would go about it is pretty much how the question originally states. I prefer verbosity over strings of boolean operators, because in my opinion it makes the logic of the operation much easier to visualize.

Sean Edwards
It's still wrong after the edit...
jpalecek
well now you can happen to execute x() two times.
Johannes Schaub - litb
+3  A: 

I can't think of a way to express it more clearly or simply. It could be made shorter, but it would make it harder to understand.

le dorfier
I agree. Optimization at this level is usually best left to the compiler. This is readable which is often more important than efficiency.
Harold Bamford
+1  A: 

You know, after seeing some of the responses here, I'd have to say your original version is more readable, and certainly more understandable. The only change I'd make would be to add a little comment on the else line stating that the else case is for x <= 10.

I don't think shortening code is really that much of an issue anymore for pretty much any reason. I know if you're an old-school coder, you like to have everything as concise as possible, but we all have 100+Gb drives and compilers all collapse any of these alternatives to the same code anyway, so why not opt for readability? My 2 cents :)

Mike
The fact that the highest voted answer is wrong proves your point.
Paul Tomblin
@Paul Tomblin: haha :) I only noticed that now that you pointed it out - and you're right, that does kind prove the point, doesn't it?
Mike
+8  A: 
bool condition_satisfied = (x() > 10 ? y > 5 : z > 2);
if (condition_satisfied)
    action1(p1, p2, p3, p4);
else
    action2(p1, p2);

Or, alternatively, what Roger Lipscombe answered.

Daniel Daranas
+2  A: 

since x() is expensive, cache the result. Then combine the preconditions on action1:

int x = x();
if ((x>10 && y>5) || (x<=10 && z>2))
{
    action1(p1,p2,p3,p4);
}
else 
{
    action2(p1,p2);
}
Steven A. Lowe
+1  A: 
var valX= x();
if ((valX > 10  && y>5) || (valX<=10 && z>2))
{

        action1(p1, p2, p3, p4);
}
else
{  
        action2(p1, p2);  
}
shsteimer
Strange how people can get such easy thing wrong... should be valX<=10, not valX<=9
jpalecek
edited, thanks. that's what happens when you quickly slap an answer together without really thinking too much about it.
shsteimer