# Solving the 'if' statement problem

• First, see http://stackoverflow.com/questions/3786358/get-rid-of-ugly-if-statements. OP has some Java to clean up:

```if ( v > 10 ) size = 6;
if ( v > 22 ) size = 5;
if ( v > 51 ) size = 4;
if ( v > 68 ) size = 3;
if ( v > 117 ) size = 2;
if ( v > 145 ) size = 1;
return size;```

Then, see the many attempts at "improving" it in the answers below.

In particular, this answer deserves some kind of award.

• Excuse me. I have some code that works and is too simple. Can someone please help me complicate the crap out of it?

• To be fair, the OP's question was how to get rid of the multiple if statements. Clearly, this is the best solution:

```int k = v;
while (true)
{
switch (k--)
{
case Integer.MIN_VALUE: break;
case 10: size = 6; break;
case 22: size = 5; break;
case 51: size = 4; break;
case 68: size = 3; break;
case 117: size = 2; break;
case 145: size = 1; break;
default: continue;
}
break;
}```

• I find the accepted answer especially funny. The original code is:

```if ( v > 10 ) size = 6; if ( v > 22 ) size = 5; if ( v > 51 ) size = 4; if ( v > 68 ) size = 3; if ( v > 117 ) size = 2; if ( v > 145 ) size = 1; return size;```[/code]

```if ( v > 145 ) size = 1; else if ( v > 117 ) size = 2; else if ( v > 68 ) size = 3; else if ( v > 51 ) size = 4; else if ( v > 22 ) size = 5; else if ( v > 10 ) size = 6;```

Although it might look the same, it's actually not the same at all. What if "size" is property and the set-part has side effects? Or "v" is a property and the get-part has side effects? In the original code, those side effects would actually be triggered, while the accepted answer "skips" over some cases and eliminate the side effects. Without knowing what he actually meant to do, it's too difficult to formulate a good answer. Personally, if v and size won't have side effects, I would prefer:

```if ( v > 10 ) return 6; if ( v > 22 ) return 5; if ( v > 51 ) return 4; if ( v > 68 ) return 3; if ( v > 117 ) return 2; if ( v > 145 ) return 1;```

``` return v > 10 ? 6 : v > 22 ? 5 : v > 51 ? 4 : v > 68 ? 3 : v > 117 ? 2 : v > 145 ? 1 : 0; ```

• @pbean said:

I find the accepted answer especially funny. The original code is: [snip...]

Although it might look the same, it's actually not the same at all. What if "size" is property and the set-part has side effects? Or "v" is a property and the get-part has side effects?

Well, if that had any side effects it would be a) the real WTF, b) more or less impossible to give a correct answer and c) the OP probably wouldn't ask the question in the first place.

@pbean said:

Personally, if v and size won't have side effects, I would prefer:

```if ( v > 10 ) return 6; if ( v > 22 ) return 5; if ( v > 51 ) return 4; if ( v > 68 ) return 3; if ( v > 117 ) return 2; if ( v > 145 ) return 1;```

But your code is actually not the same at all. It can never reach the cases for v > 22 etc. That's the whole reason the accepted answer has the statements reversed.

•  This is Java, pbean.  It does not have hidden side-effects like C#.

• @topspin said:

@pbean said:

Personally, if v and size won't have side effects, I would prefer:

```if ( v > 10 ) return 6; if ( v > 22 ) return 5; if ( v > 51 ) return 4; if ( v > 68 ) return 3; if ( v > 117 ) return 2; if ( v > 145 ) return 1;```

But your code is actually not the same at all. It can never reach the cases for v > 22 etc. That's the whole reason the accepted answer has the statements reversed.

Is there already an Internet law that says:

1) Whenever a story is posted with a code sample, people in the comments will try to rewrite the code sample-- regardless of the intent of the story! (That is, even if the story is: "wow isn't this code the worst thing ever, we already fixed it 3 years ago, and nobody uses that software anymore", someone will write the code how they would have done it, ignoring that it's already fixed.) For a practical example, see Atwood's FizzBuzz post, most of the comments being people who missed the entire point of the article writing fizzbuzz code in various languages.

2) A majority of the code samples submitted as a result of rule 1 will be wrong. Again, look at the fizzbuzz post... the comments that aren't adding new code snippets to the din are pointing out how other people's code snippets don't work right.

We should call it the WTF Law.

•  In blatant disregard of blakeyrat, I have a rewrite, unfortunately more in C++ style than Java, but whatever, you Java freaks have arrays, right?

int map[6] = { 145, 117, 68, 51, 22, 10 };

for (int i = 1; i <= 6; ++i)

if (v > map[i-1]) break;

if (i <= 6 ) size = i;

else Dammit();

• @blakeyrat said:

1) Whenever a story is posted with a code sample, people in the comments will try to rewrite the code sample-- regardless of the intent of the story! (That is, even if the story is: "wow isn't this code the worst thing ever, we already fixed it 3 years ago, and nobody uses that software anymore", someone will write the code how they would have done it, ignoring that it's already fixed.) For a practical example, see Atwood's FizzBuzz post, most of the comments being people who missed the entire point of the article writing fizzbuzz code in various languages.

I thought programmers were creative folk. Surely there are better, more interesting problems to solve… even problems needing a solution!
@blakeyrat said:
2) A majority of the code samples submitted as a result of rule 1 will be wrong. Again, look at the fizzbuzz post... the comments that aren't adding new code snippets to the din are pointing out how other people's code snippets don't work right.

Then again, maybe they need to be practicing fizzbuzz…

• @Enterprise Architect said:

I thought programmers were creative folk. Surely there are better, more interesting problems to solve… even problems needing a solution!

I think they're more interested in showing people how smart they are. "Oh, your interviewees can't do it? Look how easy it is for me, a super-genius with a huge dick!!!" The parts they miss are:

1) Nobody gives a shit, since the article wasn't "how do I write this code" but "let's talk about how so many people who claim to be programmers can't write a program" (i.e. they utterly missed the point)

2) It's really, really rude to spam the comments with code samples when nobody wants or needs them. This happens on the DailyWTF main page as well, but I can usually tolerate it because it's still funnier than those morons who just post stuff like this, which is basically comedy cancer.

@Enterprise Architect said:

Then again, maybe they need to be practicing fizzbuzz…

What they need is humility.

• @topspin said:

But your code is actually not the same at all. It can never reach the cases for v > 22 etc. That's the whole reason the accepted answer has the statements reversed.

Reading the various answers, I thought it was interesting that everybody came up with all sorts of fancy "improvements" but even the person who posts the "accepted" answer never actually mentions that the original code won't work because any vaule of v greater than 10 will always return 6.  I think the OP has a bigger problem than "how do get rid of all those if statements".

• @smxlong said:

In blatant disregard of blakeyrat, I have a rewrite, unfortunately more in C++ style than Java, but whatever, you Java freaks have arrays, right?

That's way too simple to be valid C++. Let's throw a template in there for good measure:

```template <typename T>
class Mapper {
private:
typedef std::map<T, T> map_t;
map_t mapping;
public:
void addMapping(T x, T y) {
mapping[x] = y;
}
T operator() (T x) const {
typename map_t::const_iterator entry = mapping.end();
for (typename map_t::const_iterator i = mapping.begin(); i != mapping.end(); ++i) {
if (i->first >= x)
break;
entry = i;
}
return entry == mapping.end() ? 0 : entry->second;
}
};
// ...
Mapper<int> mapper;
This still seems too simple though…

• @El_Heffe said:

Reading the various answers, I thought it was interesting that everybody came up with all sorts of fancy "improvements" but even the person who posts the "accepted" answer never actually mentions that the original code won't work because any vaule of v greater than 10 will always return 6.

I think you might want to read the code again. Also, I'm surprised nobody has pointed out that my code isn't correct either.

• @El_Heffe said:

]

Reading the various answers, I thought it was interesting that everybody came up with all sorts of fancy "improvements" but even the person who posts the "accepted" answer never actually mentions that the original code won't work because any vaule of v greater than 10 will always return 6.  I think the OP has a bigger problem than "how do get rid of all those if statements".

Only if you're standing on your head. After checking if v> 10, and setting state to 6, it'll then check if v is higher than 22, and overwrite the 6 with a 5.

•  Right.  I was thinking the code exited after the first hit.

• @Enterprise Architect said:

@smxlong said:
In blatant disregard of blakeyrat, I have a rewrite, unfortunately more in C++ style than Java, but whatever, you Java freaks have arrays, right?

That's way too simple to be valid C++. Let's throw a template in there for good measure:

```template <typename T>
class Mapper {
private:
typedef std::map<T, T> map_t;
map_t mapping;
public:
void addMapping(T x, T y) {
mapping[x] = y;
}
T operator() (T x) const {
typename map_t::const_iterator entry = mapping.end();
for (typename map_t::const_iterator i = mapping.begin(); i != mapping.end(); ++i) {
if (i->first >= x)
break;
entry = i;
}
return entry == mapping.end() ? 0 : entry->second;
}
};
// ...
Mapper<int> mapper;

This still seems too simple though…

Runing swig over the resulting object and adding a webservice server in perl that wraps the functionality should help...

• @Faxmachinen said:

Also, I'm surprised nobody has pointed out that my code isn't correct either.

It's off by one?
Whatever, it doesn't satisfy Blakey's WTF law as it was meant to be funny instead of "Hey, look! I can has if statement!!1!"

• I wonder why noone has yet come up with the arithmetic branchless solution:

size=(size-6)*(v<=10)+6-(v>22)-(v>51)-(v>68)-(v>117)-(v>145);
return size;

• @Enterprise Architect said:

```template <typename T>
class Mapper {
private:
typedef std::map<T, T> map_t;
map_t mapping;
public:
Mapper & addMapping(T x, T y) {
mapping[x] = y;
return *this;
}
T operator() (T x) const {
typename map_t::const_iterator entry = mapping.end();
for (typename map_t::const_iterator i = mapping.begin(); i != mapping.end(); ++i) {
if (i->first >= x)
break;
entry = i;
}
return entry == mapping.end() ? 0 : entry->second;
}
};
// ...
Mapper<int> mapper

FTFY. Haven't you heard of fluent interfaces?

Also, I must express my love for Faxmachinen's code.

EDIT: dang, Fax's code doesn'w work. But it looked good at first glance.

• @Zecc said:

@Enterprise Architect said:
```template <typename T, T DEFAULT = T(), typename Compare = std::less<T>,
typename Alloc = std::allocator<void> >
class Mapper {
private:
typedef std::map<T, T, Compare, Alloc> map_t;
map_t mapping;
public:
Mapper & addMapping(T x, T y) {
mapping[x] = y;
return *this;
}
T operator() (T x) const {
typename map_t::const_iterator entry = mapping.end();
Compare compare;
for (typename map_t::const_iterator i = mapping.begin(); i != mapping.end(); ++i) {
if (!compare(i->first, x))
break;
entry = i;
}
return entry == mapping.end() ? DEFAULT : entry->second;
}
};```

FTFFY. Now with "pick your own default" goodness, a default default that works on types to which you can't cast from int, and the ability to use custom comparison functions and allocators!

I wonder why noone has yet come up with the arithmetic branchless solution:

size=(size-6)*(v<=10)+6-(v>22)-(v>51)-(v>68)-(v>117)-(v>145);
return size;

I like it.

• @Zecc said:

EDIT: dang, Fax's code doesn'w work. But it looked good at first glance.

To make it work right, swap "k--" with "--k". Or if you mean it doesn't compile, that's probably because it's Java, and also because you need to wrap it in "public static void main()" or other such nonsense.

•  That guy who posted the Mapper class has to be trolling.

• Thanks to Poe's Law, it's hard to tell… I've worked with someone this fanatical about object oriented design though. His code was of roughly equal quality to that post, too.

• The OO solution might be good if the values were user-configurable or otherwise dynamic. However, for a simple static mapping it's unnecessary bloat. Also, it should really use lower_bound to make use of std::map's O(logn) search complexity.

• This is how I would approach it in C++:

`const int sizeBorders[ ] = { 10, 22, 51, 68, 117, 145 };const size_t numBorders = sizeof(sizeBorders)/sizeof(sizeBorder[0]); const int* const sizeBordersBegin = &sizeBorders[0];const int* const sizeBordersEnd = sizeBordersBegin + numBorders;const int *  sizeIter = std::upper_bound(sizeBordersBegin, sizeBordersEnd);ptrdiff_t diff = sizeIter - sizeBordersBegin; return diff ? (size = numBorders + 1 - diff ) : size;`

Of course you could modify that by making sizeBorders a std::vector and not having the boundaries hard-coded.

With such a few of them it is not clear you actually improve speed performance using binary search rather than linear look-up as O(log N) in this case is close to 3 which is also the average number of comparisons in linear if the data is even distributed between the boundaries.

Not sure what Java has for upper_bound.

• Actually I think I should be using lower_bound because if it is equal to the boundary it goes into the lower section, and of course I forgot to put the value in it.

In Java the equivalent would be to use SortedSet. You would then probably use tailSet() and look at its size. That would give you an indication as to what size is above.

So in Java something like:

// (Do this once only)

SortedSet<int> boundaries = new SortedSet<int>;

// Do this one each lookup

SortedSet<int> subset =  boundaries.tailSet(value);

return ( subset.size() == boundaries.size() ) ? size : subset.size() + 1;

I wonder why noone has yet come up with the arithmetic branchless solution:

size=(size-6)*(v<=10)+6-(v>22)-(v>51)-(v>68)-(v>117)-(v>145);
return size;

Because it isn't branchless?

The ?: operator somewhat hides an if() statement, because something in the mind refuses to acknowledge the existence of an if() inside an expression.

The > and <= operators totally hide the if() statements.  Deep down inside the compiled code is an (if (condition) use 1 else use 0) subexpression.

• The "if" constructs aren't the problem.

This code snippet has more magic numbers than Earvin Johnson's NBA stats.

•  "Welcome, dear Daily-WTF-readers, what an honor "

heh

• @DOA said:

"Welcome, dear Daily-WTF-readers, what an honor "

heh

heh

• @dhromed said:

@DOA said:

"Welcome, dear Daily-WTF-readers, what an honor "

heh

heh

heh?

Strangely, reputation has gone up since the WTF article. Probably not what the author had in mind. Thanks very much, "Enterprise Architect".

Oh no! What have we done?

•  @tdb said:

The OO solution might be good if the values were user-configurable or otherwise dynamic.

Of course, that's exactly what I had in mind (I am the author of this madness). It would be easy to configure such a mapper using e.g. property files using Spring, for example.

@tdb said:

However, for a simple static mapping it's unnecessary bloat. Also, it should really use lower_bound to make use of std::map's O(logn) search complexity.

The topic is Java, there is no such thing as std::map there. I agree that the search algorithm I use is way too simple (at least for large arrays), but it was just a quick tech demo after all.

• @Zecc said:

Strangely, reputation has gone up since the WTF article. Probably not what the author had in mind. Thanks very much, "Enterprise Architect".

Oh no! What have we done?

Quick! Community Wiki! Community Wiki!

Edit: It seems I spoke too soon.

•  @Cbuttius said:

In Java the equivalent would be to use SortedSet. You would then probably use tailSet() and look at its size. That would give you an indication as to what size is above.

So in Java something like:

// (Do this once only)

SortedSet<int> boundaries = new SortedSet<int>;

//...

// Do this one each lookup

SortedSet<int> subset =  boundaries.tailSet(value);

return ( subset.size() == boundaries.size() ) ? size : subset.size() + 1;

This won't compile, as I write in my comment to your SO answer. Also, it's roughly equivalent to my solution in complexity, but only delivers correct results for target sizes 1 to 6. What if the target sizes were 2, 5, 7, 11, 23 and 44? You'd have to throw away your solution while in mine you'd just adjust the input parameters.

• @Enterprise Architect said:

Edit: It seems I spoke too soon.

Yup, I'm here. But I don't think I'll stay long.

• @Enterprise Architect said:

His code was of roughly equal quality to that post, too.

That good, huh? Most have been fun working with him.

• @Zecc said:

Strangely, reputation has gone up since the WTF article. Probably not what the author had in mind. Thanks very much, "Enterprise Architect".

Oh no! What have we done?

In all seriousness, I kind of agree it is a bit unfair that barjak's answer got up-voted while yours didn't (talking to mostlymagic here, not myself).

Except barjak is reusing an existing API (I think), and:

``s.put(10, 6);s.put(22, 5);s.put(51, 4);s.put(68, 3);s.put(117, 2);s.put(145, 1);``

``Mapper    .from(10, 22, 51, 68, 117, 145)    .to  ( 6,  5,  4,  3,   2,   1);``

IMO.  EDIT: Then again, maybe not. I retract this part, but leave it anyway for your reference.

But, quoting badp: "It screams OVERKILL..."   This applies to both of your solutions.

Heck, even the array solutions seem worse than using the bunch-of-ifs.

• @mostlymagic said:

This won't compile, as I write in my comment to your SO answer. Also, it's roughly equivalent to my solution in complexity, but only delivers correct results for target sizes 1 to 6. What if the target sizes were 2, 5, 7, 11, 23 and 44? You'd have to throw away your solution while in mine you'd just adjust the input parameters.

If those were the target sizes yes, you would use a map, but it looks like the intention here is to bucket according to the input range using consecutive bucket numbers. If they decided to insert another bucket you would need to modify all your values while I would put in one add statement.

And yes, it is the same in complexity, both are O(log N), although with 6 buckets, log(N) is about 3 lookups and linear is the same on average although it's 6 in worst-case scenario, and we don't know that the data input is going to be evenly distributed. (Of course the original code always uses 6 comparisons).

By the way if you are going to count sorted data input coming in and there is a lot of it, it is far more efficient to search for the boundaries in the data than search for the data in the boundaries. For example you have 32K sorted values and 8 buckets. So to search in the 32K sorted values for 8 buckets is 8*15=120. Searching the other way is 96K. Linear "set-intersect" is 32K + 8 which...

• @mostlymagic said:

@Enterprise Architect said:

His code was of roughly equal quality to that post, too.

That good, huh? Most have been fun working with him.

Why yes. His code worked so well that, just to feel better about my own abilities, I had to re-write large chunks of it so I could call them my own. </sarcasm>

• @smxlong said:

you Java freaks have arrays, right

Yes, we have arrays. But we don't like to use them as they're a usability nightmare.

• @Cbuttius said:

By the way if you are going to count sorted data input coming in and there is a lot of it, it is far more efficient to search for the boundaries in the data than search for the data in the boundaries. For example you have 32K sorted values and 8 buckets. So to search in the 32K sorted values for 8 buckets is 8*15=120. Searching the other way is 96K. Linear "set-intersect" is 32K + 8 which...

Yes, obviously. As I keep writing all over the place: this was a quick tech demo without optimization. What you are suggesting is exactly the way I'd done it if this were production code and not a quick hack for SO.

BTW: if this were production code, then maybe an entry in DailyWTF would be justified.

• @Enterprise Architect said:

Why yes. His code worked so well that, just to feel better about my own abilities, I had to re-write large chunks of it so I could call them my own. </sarcasm>

Yup, I guess we all know that kind. But in my experience that usually results from a lack of object orientation, not from too much of it. Or that guy has seriously misunderstood object orientation.

• @Schlagwerk said:

That guy who posted the Mapper class has to be trolling.

I think the OP (at stack overflow) was trolling.

• @mostlymagic said:

@Enterprise Architect said:

Why yes. His code worked so well that, just to feel better about my own abilities, I had to re-write large chunks of it so I could call them my own. </sarcasm>

Yup, I guess we all know that kind. But in my experience that usually results from a lack of object orientation, not from too much of it. Or that guy has seriously misunderstood object orientation.

Object oriented programming is great, generally. It's just the nutty architecture astronauts that ruin things for the rest of us, especially when they're great at abstract thinking but fail miserably at writing actual working code.

• @Cbuttius said:

This is how I would approach it in C++:

[stuff with] upper_bound.

@Cbuttius said:
Actually I think I should be using lower_bound because if it is equal to the boundary it goes into the lower section

That's exactly what's wrong with the "generalized" overkill solutions. The if statement is FAR easier to get right and doesn't require thinking about the edge cases, especially when reading the code.

• @smxlong said:

In blatant disregard of blakeyrat, I have a rewrite, unfortunately more in C++ style than Java, but whatever, you Java freaks have arrays, right?

int map[6] = { 145, 117, 68, 51, 22, 10 };

for (int i = 1; i <= 6; ++i)

if (v > map[i-1]) break;

if (i <= 6 ) size = i;

else Dammit();

This, except i needs to be declared outside the loop, and I'd use zero-indexing and just set size to i+1 to improve readability slightly.

That said, this code is still horribly inefficient and should be written as an unrolled loop in assembler.

• @Enterprise Architect said:

Object oriented programming is great, generally. It's just the nutty architecture astronauts that ruin things for the rest of us, especially when they're great at abstract thinking but fail miserably at writing actual working code.

In my opinion you need both in a good software team, and they are rarely the same persons. Nutty architecture astronauts like myself will strive to create clean interfaces, while hardcore numbercrunchers will implement the dirty details to make it efficient. The Java Collections API is a perfect example: you can clearly see that the ones who wrote the API and the ones who implemented the sorting algorithms work together great (it's both usable and reliable), but also that they are not the same persons.

So: while I agree with 90% of Joel's pieces, I would take this one with a grain of salt. First of all: a lot of what he is complaining about is not Architect Speak, it's Marketing Speak (and I guess all Developers hate that). But, to stick with the Architect metaphor: you need both a good architect and good builders to build a house. If the Builders are bad, the walls will fall down. If the Architect is bad, no one will ever want to live there. Both are undesirable, especially from a business viewpoint.

I think one important aspect of software development (and probably any other creative process) is being able to delegate tasks. Do the things you are good at and let others do what they are good at. Joel seems to think that anbody who doesn't understand pointers is a bad programmer. Sure, they'd probably be bad C / C++ programmers (because you probably need pointers to get things done in these languages, I wouldn't know, I haven't touched any C language in about 15 years). But they could still be great developers in Java, Scala, Haskell, Erlang, Groovy, JavaScript, Ruby, PERL and dozens of other languages, all of which are in production very successfully on thousands of sites. Yes, every developer must learn algorithms and theory of software engineering. But does every developer need to know what happens at machine level? No siree.

• @mostlymagic said:

In my opinion you need both in a good software team, and they are rarely the same persons. Nutty architecture astronauts like myself will strive to create clean interfaces, while hardcore numbercrunchers will implement the dirty details to make it efficient.

Back to your SO answer: if we needed a dynamic mapping, something like this might make more sense. Let's assume we do need this, and let's take it a step further: suppose we want to support adding additional partitions between the existing partitions at runtime. How do we do that with your class?

That opens another question: is it coincidence that OP's partitions map to 1-6, or should we always be mapping the input ranges in order to integers 1-N? That pesky detail could make another abstraction more appropriate.

Would you design a user interface without considering what end users are actually trying to accomplish? Why design a programming interface without considering real-world applications?

@mostlymagic said:
Yes, every developer must learn algorithms and theory of software engineering. But does every developer need to know what happens at machine level? No siree.

This is true if you don't mind having no idea what impact your high-level design is having on the machine level. This is ok sometimes.

•  Clearly the answer is to use MUMPS:

s size=\$s(v>145:1,v>117:2,v>68:3,v>51:4,v>22:5,v>10:6,1:0)

Looks like your connection to What the Daily WTF? was lost, please wait while we try to reconnect.