Avoiding If Statement Inside a for Loop

Avoiding if statement inside a for loop?

Pass in the body of the loop as a functor. It gets inlined at compile-time, no performance penalty.

The idea of passing in what varies is ubiquitous in the C++ Standard Library. It is called the strategy pattern.

If you are allowed to use C++11, you can do something like this:

#include <iostream>
#include <set>
#include <vector>

template <typename Container, typename Functor, typename Index = std::size_t>
void for_each_indexed(const Container& c, Functor f, Index index = 0) {

for (const auto& e : c)
f(index++, e);
}

int main() {

using namespace std;

set<char> s{'b', 'a', 'c'};

// indices starting at 1 instead of 0
for_each_indexed(s, [](size_t i, char e) { cout<<i<<'\t'<<e<<'\n'; }, 1u);

cout << "-----" << endl;

vector<int> v{77, 88, 99};

// without index
for_each_indexed(v, [](size_t , int e) { cout<<e<<'\n'; });
}

This code is not perfect but you get the idea.

In old C++98 it looks like this:

#include <iostream>
#include <vector>
using namespace std;

struct with_index {
void operator()(ostream& out, vector<int>::size_type i, int e) {
out << i << '\t' << e << '\n';
}
};

struct without_index {
void operator()(ostream& out, vector<int>::size_type i, int e) {
out << e << '\n';
}
};

template <typename Func>
void writeVector(const vector<int>& v, Func f) {
for (vector<int>::size_type i=0; i<v.size(); ++i) {
f(cout, i, v[i]);
}
}

int main() {

vector<int> v;
v.push_back(77);
v.push_back(88);
v.push_back(99);

writeVector(v, with_index());

cout << "-----" << endl;

writeVector(v, without_index());

return 0;
}

Again, the code is far from perfect but it gives you the idea.

Avoiding Conditional Statements in Loops

You can use the intrinsic min and max functions for this.

As they are both elemental, you can use them on the whole array, as

b1_dotProd = max(-1.0_dp, min(b1_dotProd, 1.0_dp))

While there are processor instructions which allow min and max to be implemented without branches, it will depend on the compiler implementation of min and max as to whether or not this is actually done and if this is actually any faster, but it is at least a lot more concise.

Avoid checking the same condition every step in a loop in C++

First of all, profile to see if it matters. If it does, you have several options:

  • Cache the constant outside of the loop if the compiler hasn't done so already. This is the simplest and in most cases, enough:

    const bool constant_condition = ...;
    for (...) {
    ...
    if (constant_condition) do_something(...);
    }
  • If you really need to avoid the branch, a typical approach is to define an auxiliary function or a local lambda (C++11) to factor out the common blocks of code. However, this still duplicates code and, depending on the case, may not look pretty at all:

    auto main_work = [...](...) { ... };
    if (constant_condition)
    for (...) { main_work(...); }
    else
    for (...) { main_work(...); do_something(...); }
  • Define a template and parametrize as needed. The compiler will typically optimize properly, so you can simply copy-paste the code. If you really want to ensure the branch is removed, you can force it specializing the template, or taking advantage of if constexpr (C++17) etc. However, beware of code bloat and compilation times.

    template <bool constant_condition>
    void f(...) { ... }

    if (constant_condition)
    f<true>(...);
    else
    f<false>(...);

Finally, don't forget to profile again. Sometimes, removing a branch may look good, yet be detrimental overall. This is specially true if the code changes a lot and what initially looked like a small duplication of instructions is now several memory pages full of duplicated code.

Another alternative is trying to see if the algorithm/code can be written as branchless instead; however, that isn't a general solution.

How can I avoid for loops with an if condition inside them with C++?

IMHO it's more straight forward and more readable to use a for loop with an if inside it. However, if this is annoying for you, you could use a for_each_if like the one below:

template<typename Iter, typename Pred, typename Op> 
void for_each_if(Iter first, Iter last, Pred p, Op op) {
while(first != last) {
if (p(*first)) op(*first);
++first;
}
}

Usecase:

std::vector<int> v {10, 2, 10, 3};
for_each_if(v.begin(), v.end(), [](int i){ return i > 5; }, [](int &i){ ++i; });

Live Demo

Nested IF inside FOR loop works only for first value

What happens here is that a return statement causes the function to exit at the point where it is reached. As such, after the first instance of the loop, since the condition is not satisfied the if-else block returns and the function execution ends.

What you want to do here is return "no such contact" after the loop is done and every check has been executed. As such:

function lookUpProfile(firstName, attribute){
for (i = 0; i < people.length; i++) {
if (firstName == people[i].firstName && firstName == people[i].firstName) {
return (people[i][attribute]);
}
}
return "No such contact";
}

This code will execute the loop, checking each person in the array for the condition. If any of them match it returns, otherwise it returns after they have all been checked.

Edit: Since you need your final return statement to be conditioned, you will want to use the else block to set a flag that identifies which condition wasn't met:

function lookUpProfile(firstName, prop) {
var firstNameFound = false;
for (i = 0; i < people.length; i++) {
if (firstName == people[i].firstName && prop == people[i].hasOwnProperty(prop)) {
return (people[i][prop]);
}
else {
if (firstName == people[i].firstName) firstNameFound = true;
}
}
if (firstNameFound) return "No such property";
else return "No such contact";
}

Edit 2: Only a single flag is needed here. If the loop finished and it is set, we can assume that the second condition fails, as the name is tested first.

Edit 3: Fixed a couple mistakes. Here's a working JSFiddle with the same code as above: https://jsfiddle.net/bfhev7gL/16/

Edit 4: To answer your last question about the second if line, the variable (which was formerly assigned false during initialization) is assigned the value true if the check for first name existing is met. As the result of this conditional can be resolved in a single line, we can simply append the line after it without the need to wrap it in braces.

At the end of the loop, we can affirm that if it is assigned then at least one firstName matched, but since the loop finished and did not return then prop did not match when firstName did. Then we can condition the error return around it; if firstName matched we inform the user that prop did not, otherwise firstName wasn't found to begin with and we can inform the user of that instead.

Python - Any way to avoid several if-statements inside each other in a for-loop?

When you have three or more numbered and similarly-used variables, think lists.

With that in mind, we first change list1, list2, list3, ... into a list of lists (indexed 0,1,2,3 instead of 1,2,3,4). Except don't call it list, because that's a useful name for something that's already useful. lst is pretty popular in Python. I'm also going to change list5 into lstA and list6 into lstB because 5 and 6 no longer make sense.

Now we have this:

for H in range(0,len(a_list)):
if a_list[H] > lst[3][0]:
lstA = [number_list[i]]
if function(lst[0],lstA) == lst[0][1]:
if function(lst[1],lstA)== lst[1][1]:
if function(lst[2],lstA)== lst[2][1]:
if function(lst[3],lstA)== lst[3][1]:
lstA.append(input('some input from the user'))
other_function(lstA)
if lstA[1]== 40:
print ('something something')
break out of EVERY loop
else:
for H in range(0,len(a_list)):
if a_list[H] > lstA[0]:
lstB = [number_list[i]]
if function(lst[0],lstB) == lst[0][1]:
if function(lst[1],lstB)== lst[1][1]:
if function(lst[2],lstB)== lst[2][1]:
if function(lst[3],lstB)== lst[3][1]:
if function(lstA,lstB)== lstA[1]:
lstB.append(input('some input from theuser'))
other_function(lstB)
if lstB[1]== 40:
print ('something something')
break out of EVERY loop
else:
etc. (one extra comparison every time)

Now it's more obvious that we're basically doing the same thing four times.


When you have to do the same thing a bunch of times, think loops.

We'll change the blocks into loops. We'll also use a flag variable to keep track of whether something failed while testing our logic, and use the logic "if it does not work, skip stuff" rather than "if it works, do stuff"

for H in range(0,len(a_list)):
if a_list[H] > lst[3][0]:
continue #reducing indent levels by negating the check:
#quit on failure instead of work on success

lstA = [number_list[i]]

quit = False

for j in range(4):
if function(lst[j],lstA) != lst[j][1]: #testing FALSEHOOD
quit = True
break #the j loop only

if quit:
continue #reducing indent levels by negating the check

lstA.append(input('some input from the user'))
other_function(lstA)
if lstA[1]== 40:
print ('something something')
break #out of EVERY loop
#else: #don't need the else because we broke

for H in range(0,len(a_list)):
if not a_list[H] > lstA[0]:
continue #reducing indent levels by negating the check

lstB = [number_list[i]]

for j in range(4):
if function(lst[j],lstB) != lst[j][1]: #testing FALSEHOOD
quit = True;
break #to the H loop
if not quit and function(lstA,lstB)== lstA[1]: #combining two checks
lstB.append(input('some input from theuser'))
other_function(lstB)
if lstB[1]== 40:
print ('something something')
break #out of EVERY loop
else: #at this point I'm lost and can't refactor
etc. (one extra comparison every time)

When you have to break out of multiple loops at once, think functions and returning instead of breaking. Or exceptions and try blocks, but some might find that distasteful.

The failure flag works, but isn't very elegant. There's an exaggerated saying: "... if you need more than 3 levels of indentation, you're screwed anyway, and should fix your program." Read this as: If you have a lot of levels of indentation (and some languages require more than others), you should think about whether you can move some of the logic into a function.

We'll also move some repeated logic into a checker function.

(Finally, I think it's a bug that your second for-loop is nested in your first. Since they have the same iterator variable H, I think that would cause an infinite loop. So I fixed that.)

#returns FALSE if a check fails, unlike the `quit` variable
def checker(lst, lstA):
for i in range(4):
if function(lst[i],lstA) != lst[i][1]: #testing FALSEHOOD
return False;
return True;

def main(???):
for H in range(0,len(a_list)):
if a_list[H] > lst[3][0]:
continue

lstA = [number_list[i]]

if not checker(lst,lstA):
continue

lstA.append(input('some input from the user'))
other_function(lstA)
if lstA[1]== 40:
print ('something something')
return #break out of EVERY loop

for H in range(0,len(a_list)):
if not a_list[H] > lstA[0]:
continue

lstB = [number_list[i]]

if checker(lst,lstB) and function(lstA,lstB) == lstA[1]:
lstB.append(input('some input from theuser'))
other_function(lstB)
if lstB[1]== 40:
print ('something something')
return # break out of EVERY loop
else: #at this point I'm lost and can't refactor
etc. (one extra comparison every time)


Related Topics



Leave a reply



Submit