0

I did the due-diligence to see if this has been asked before and didn't find anything identical but close, so here goes.

Say I have a chain of if-else-if statements.

foreach (value in valueList)
    if (value == 120) {
        w = true;
    } else if (value == 140) {
        x = true;
    } else if (value == 160) {
        y = true;
    } else if (value == 180) {
        z = true;
    }
}

Is there any advantage of changing the else-if chain to ternary expressions such as:

foreach (value in valueList) {
    w = (value == 120) ? true : false;
    x = (value == 140) ? true : false;
    y = (value == 160) ? true : false;
    z = (value == 180) ? true : false;
}

My first inclination is no. Because of the for loop every assignment is made each time the loop happens. Whereas in the if-else-if chain, the assignment is made only once. But the comparisons are made more often (right?). Can anybody settle this for me?

I know a switch would easily defeat the both in terms of performance. Can I base this question on the assumption that using switch is not an option?

I guess another question inside this question would be what are the Big-O comparisons between the two?

gh0st
  • 1,653
  • 3
  • 27
  • 59
  • 3
    what about using a `switch`? – Luis Lavieri May 15 '15 at 17:15
  • Switch easily beats the both, I thought I mentioned that...nope. – gh0st May 15 '15 at 17:15
  • 2
    These are not equivalent. If `valuelist` contains all four numbers, in order, after the first loop all four variables will be true. After the second loop, only `z` will be true. – Paul Roub May 15 '15 at 17:16
  • 1
    In the ternary case, you're performing every comparison for all values, so naturally that will result in more operations (sans any optimizations). On top of that, they're not logically equivalent - e.g. if the last value is 180, only z is true in the ternary case, whereas in the initial case it depends on the previous values. – Gene May 15 '15 at 17:17
  • 1
    And a decent optimizer will likely turn the `if...else` chain into *exactly* the same code as an equivalent switch. – Paul Roub May 15 '15 at 17:17
  • I didn't realize that about the loop @PaulRoub. I was trying to generalize actual code... – gh0st May 15 '15 at 17:19
  • @PaulRoub That transformation wouldn't be valid, as it'd be functionally changing what the code does, so no, any decent C# optimizer *wouldn't* do that. An `if/else` chain evaluates arbitrary boolean expressions sequentially until one is met, and then execute a statement, a `switch` creates a hash table mapping compile time constants to actions to perform, and does a lookup based on the value being switched on. – Servy May 15 '15 at 17:20
  • @Servy A switch with the same four cases, performing the same four assignments, is functionally different from the if-else chain *how*? – Paul Roub May 15 '15 at 17:25
  • @PaulRoub It's not a valid transformation in the general case; in very rare special cases it can be valid. In this *particular* case, the difference between the two is going to be cosmetic, not functional, because the number of items is small, so it wouldn't even matter. The `switch` would be transformed into the `if/else` chain by the compiler, not the other way around. – Servy May 15 '15 at 17:28

4 Answers4

2

Note that both solutions are very different. The first one only assigns true to one of those four variables while the other one will overwrite whatever value all four of them had before.

That being said, using the ternary operator in the second code is really bad. You can just assign the result of the comparison directly:

w = value == 120;
x = value == 140;
y = value == 160;
z = value == 180;

Taking aside the semantics, this will also make it likely a bit more performant than a if/else structure. You might think that just running a single comparison will make it faster, so the first solution should be better, but in fact, branching can be slow. And since comparison operations are actually really fast, just assigning the result of a comparison four times is likely “faster”.

Note that none of this will actually have any real performance impact. Both is very low-level and it’s very likely that you have something else in your application’s code that is way slower, being a likelier bottle neck. So I wouldn’t stress about using one or another way for performance here; just choose what is semantically correct and then use whatever solution makes the semantics as clear as possible.

I know a switch would easily defeat the both in terms of performance.

A switch statement gives you the same effect as a chain of ifs and elses, so there isn’t really a difference here.

I guess another question inside this question would be what are the Big-O comparisons between the two?

Both is linear, as you just loop through the list. Every other difference is constant, so it doesn’t matter in Big-O notation.

Community
  • 1
  • 1
poke
  • 369,085
  • 72
  • 557
  • 602
  • This explanation was what I was really looking for. After reading the other answers in their entirety I may decide to mark this as the answer. – gh0st May 15 '15 at 17:27
  • @gh0st What's the point of understanding the difference in performance of things that do completely different things? You still have to do whichever one gives you the result that you want, not the one that you think will perform better (not that there's going to be any meaningful performance difference, as the answer mentions, because the differences are going to be way too small to even notice). – Servy May 15 '15 at 17:29
  • @Servy, I understand what you're saying. I need to do some debugging. – gh0st May 15 '15 at 17:34
1

The two function entirely differently. Performance is irrelevant; they don't do the same thing.

The first snippet sets the appropriate variable to true if the condition is met, and does nothing if the corresponding condition isn't met, meaning it leaves the original value.

The second snippet assigns a value to each variable on each iteration.

So the first snippet is effectively asking, "is any value equal to this number" for each of the numbers, the second snippet is effectively asking, "is the last value equal to this number" for each of the numbers. I assume you intend the former, not the latter, so the latter is simply wrong.

Servy
  • 202,030
  • 26
  • 332
  • 449
  • I'm trying to generalize production code in my question. Seems I didn't do it accurately enough. – gh0st May 15 '15 at 17:20
0

Well, in the case of integers, I really like to use a switch when I have too many cases. @ima explains it in this answer. Otherwise, it only matters what looks better or more "readable"

However using a switch with strings is a totally different story as explained in this post.

Community
  • 1
  • 1
Luis Lavieri
  • 4,064
  • 6
  • 39
  • 69
0

To avoid unnecessary assignments use them inside the ternary operator. To escape condition use empty if pattern.

foreach (var value in valueList)
    if (value == 120 ? w = true : value == 140 ? x = true : value == 160 ? y = true : value == 180 ? z = true : false) ;

Operands inside ternary operator are evaluated only if the corresponding condition is met.

Reverin
  • 49
  • 8