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
Converting Narrow String to Wide String
Why Is There No Piecewise Tuple Construction
Project Euler Problem 12 - C++
How to Overload Operator==() for a Pointer to the Class
Error Lnk2019 Unresolved External Symbol
Simple String Parsing with C++
Wait for Input for a Certain Time
Format Curly Braces on Same Line in C++ VScode
How to Generate and Run Native Code Dynamically
Sizeof an Array Passed as Function Argument
How Is This a Most Vexing Parse
Undefined Reference to Template Members
Is Static Init Thread-Safe with Vc2010
Why Do I Need to Repeat Template Arguments of My Base Class in Member Initalizer List