Nested range-based for-loops - c++

I have the following code using range-based for-loops (C++11):
vector<atom> protein;
...
for(atom &atom1 : protein) {
...
for(atom &atom2 : protein) {
if(&atom1 != &atom2) {
...
}
}
}
Is there a better/cleaner/faster way to write this nested loops? Isn't there a way to include the if condition in the second loop?

Similar to ronag's answer is a more generic version:
template<typename C, typename Op>
void each_unique_pair(C& container, Op fun)
{
for(auto it = container.begin(); it != container.end() - 1; ++it)
{
for(auto it2 = std::next(it); it2 != container.end(); ++it2)
{
fun(*it, *it2);
fun(*it2, *it);
}
}
}
UPDATE
template<typename C, typename O1, typename O2>
void each_value_and_pair(C& container, O1 val_fun, O2 pair_fun)
{
auto it = std::begin(container);
auto end = std::end(container);
if(it == end)
return;
for(; it != std::prev(end); ++it)
{
val_fun(*it);
for(auto it2 = std::next(it); it2 != end; ++it2)
{
pair_fun(*it2, *it);
pair_fun(*it, *it2);
}
}
}
Which is used like this:
main()
{
std::vector<char> values;
// populate values
// ....
each_value_and_pair(values,
[](char c1) { std::cout << "value: " << c1 << std::endl;},
[](char c1, char c2){std::cout << "pair: " << c1 << "-" << c2 << std::endl;});
}

Sad but true.
How about normal loops with iterators and auto keyword?

I think this might be what you are looking for:
for(auto it1 = std::begin(protein1); it1 != std::end(protein); ++it1)
{
for(auto it2 = std::next(it1); it2 != std::end(protein); ++it2)
{
auto& atom1 = *it1;
auto& atom2 = *it2;
// ...
}
}

you're method is just fine.
if you want to save the if statement you can
vector<atom> protein;
int i, j;
...
for(i = 0; i < protein.size() : i++) {
atom &atom1 = protein.at(i);
for(j = i+1; j < protein.size() ; j++) {
atom &atom2 = protein.at(j);
// Do something
// Swap the atom2 and atom1
// Do something again
}
}

Related

Efficient way to find intersection of two vectors with respect to two members of vector objects

I have two vectors holding data objects. Each data object is holding coordinates and some other data. The vectors will always be sorted (first for the x coordinates and then for the y coordinates). I'm trying to delete all objects from both vectors that have coordinates that can not be found in both of the vectors. Here's an MWE of what I'm currently doing:
#include <iostream>
#include <vector>
#include <algorithm>
struct foo{
foo()=default;
foo(int x, int y, double data):x(x),y(y),data(data){}
int x;
int y;
double data;
};
int main()
{
std::vector<foo> vec1=std::vector<foo>(7);
std::vector<foo> vec2=std::vector<foo>(4);
vec1={foo(1,1,0.),foo(1,2,0.),foo(2,1,0.),foo(2,2,0.),foo(2,3,0.),foo(3,1,0.),foo(3,2,0.)};
vec2={foo(1,2,0.),foo(1,3,0.),foo(2,1,0.),foo(3,1,0.)};
for(auto it1=vec1.begin(); it1!=vec1.end();){
auto cur_element=*it1;
auto intersec = std::find_if(vec2.begin(),vec2.end(),[cur_element]
(foo & comp_element)->bool{
return((cur_element.x==comp_element.x) && (cur_element.y==comp_element.y));
});
if(intersec==vec2.end()) it1=vec1.erase(it1);
else ++it1;
}
for(auto it2=vec2.begin(); it2!=vec2.end();){
auto cur_element=*it2;
auto intersec = std::find_if(vec1.begin(),vec1.end(),[cur_element]
(foo & comp_element)->bool{
return((cur_element.x==comp_element.x) && (cur_element.y==comp_element.y));
});
if(intersec==vec1.end()) it2=vec2.erase(it2);
else ++it2;
}
std::cout<<"vec1:\n";
for(auto i: vec1) std::cout<<i.x<<" "<<i.y<<"\n";
std::cout<<"\nvec2:\n";
for(auto i: vec2) std::cout<<i.x<<" "<<i.y<<"\n";
return 0;
}
It works and gives me the expected output.
Anyway it seems really unefficient having to loop through both of the vectors. Is there a more efficient way to achieve the same output?
EDIT: It's not enough to obtain the coordinates that are represented in both vectors. What I need is an efficient way to delete the "wrong" objects from both vectors.
Your two vectors are sorted already – perfect!
First, assuming a comparison function (with up-coming C++20, this would get the space-ship operator...):
int compare(foo const& l, foo const& r)
{
return l.x != r.x ? l.x - r.x : l.y - r.y;
}
Now you can use it in the algorithm:
auto i1 = v1.begin();
auto i2 = v2.begin();
auto end1 = i1;
auto end2 = i2;
while(i1 != v1.end() && i2 != v2.end())
{
int cmp = compare(*i1, *i2);
if(cmp < 0)
{
// skip element
++i1;
}
else if(cmp > 0)
{
++i2;
}
else
{
// matching element found, keep in both vectors...
if(i1 != end1)
*end1 = std::move(*i1);
++i1;
++end1;
if(i2 != end2)
*end2 = std::move(*i2);
++i2;
++end2;
// if you can rely on move (or fallback copy) assignment
// checking for self assignment, the following simpler
// alternative can be used instead:
//*end1++ = std::move(*i1++);
//*end2++ = std::move(*i2++);
}
}
v1.erase(end1, v1.end());
v2.erase(end2, v2.end());
Linear in both vectors...
The algorithm just moves the elements to be kept to front and finally drops all the overdue ones – similarly as would std::remove_if do...
I think this solution is linear and does what you want.
Possible further enhancement:
for large vectors with large areas of non-intersection, it may be worth caching regions to erase.
another strategy if data is cheap to move, is to conditionally build output vectors from input vectors and swap
struct foo_less
{
bool operator()(foo const&l, foo const& r) const
{
return std::tie(l.x, l.y) < std::tie(r.x, r.y);
}
};
void remove_non_matching(std::vector<foo>& l, std::vector<foo>& r)
{
constexpr auto less = foo_less();
assert(std::is_sorted(l.begin(), l.end(), less));
assert(std::is_sorted(r.begin(), r.end(), less));
auto lcurrent = l.begin(), rcurrent = r.begin();
while (lcurrent != l.end() && rcurrent != r.end())
{
if (less(*lcurrent, *rcurrent))
lcurrent = l.erase(lcurrent);
else if(less(*rcurrent, *lcurrent))
rcurrent = r.erase(rcurrent);
else
{
++lcurrent;
++rcurrent;
}
}
l.erase(lcurrent, l.end());
r.erase(rcurrent, r.end());
}
alternative approach will cost more memory but is theoretically more efficient:
void remove_non_matching_alt(std::vector<foo>& l, std::vector<foo>& r)
{
constexpr auto less = foo_less();
assert(std::is_sorted(l.begin(), l.end(), less));
assert(std::is_sorted(r.begin(), r.end(), less));
auto lresult = std::vector<foo>(), rresult = std::vector<foo>();
auto sz = std::min(l.size(), r.size());
lresult.reserve(sz);
rresult.reserve(sz);
auto lcurrent = l.begin(), rcurrent = r.begin();
while (lcurrent != l.end() && rcurrent != r.end())
{
if (less(*lcurrent, *rcurrent))
++lcurrent;
else if(less(*rcurrent, *lcurrent))
++rcurrent;
else
{
lresult.push_back(std::move(*lcurrent++));
rresult.push_back(std::move(*rcurrent++));
}
}
l.swap(lresult);
r.swap(rresult);
}
Similar but uses a thread_local persistent cache to avoid un-necessary memory allocations:
void remove_non_matching_alt_faster(std::vector<foo>& l, std::vector<foo>& r)
{
constexpr auto less = foo_less();
assert(std::is_sorted(l.begin(), l.end(), less));
assert(std::is_sorted(r.begin(), r.end(), less));
// optimisation - minimise memory allocations on subsequent calls while maintaining
// thread-safety
static thread_local auto lresult = std::vector<foo>(), rresult = std::vector<foo>();
auto sz = std::min(l.size(), r.size());
lresult.reserve(sz);
rresult.reserve(sz);
auto lcurrent = l.begin(), rcurrent = r.begin();
while (lcurrent != l.end() && rcurrent != r.end())
{
if (less(*lcurrent, *rcurrent))
++lcurrent;
else if(less(*rcurrent, *lcurrent))
++rcurrent;
else
{
lresult.push_back(std::move(*lcurrent++));
rresult.push_back(std::move(*rcurrent++));
}
}
l.swap(lresult);
r.swap(rresult);
// ensure destructors of discarded 'data' are called and prep for next call
lresult.clear();
rresult.clear();
}
This is my approach, in a erase–remove idiom style, iterating only once through the vectors:
#include <iostream>
#include <vector>
#include <iterator>
#include <utility>
struct foo
{
foo() = default;
foo(int x, int y, double data) : x(x), y(y), data(data) {}
int x;
int y;
double data;
};
// Maybe better as overloaded operators
int compare_foo(const foo& foo1, const foo& foo2)
{
if (foo1.x < foo2.x) return -1;
if (foo1.x > foo2.x) return +1;
if (foo1.y < foo2.y) return -1;
if (foo1.y > foo2.y) return +1;
return 0;
}
std::tuple<std::vector<foo>::iterator, std::vector<foo>::iterator>
remove_difference(std::vector<foo>& vec1, std::vector<foo>& vec2)
{
typedef std::vector<foo>::iterator iterator;
iterator it1 = vec1.begin();
size_t shift1 = 0;
iterator it2 = vec2.begin();
size_t shift2 = 0;
while (it1 != vec1.end() && it2 != vec2.end())
{
int cmp = compare_foo(*it1, *it2);
if (cmp < 0)
{
++it1;
shift1++;
}
else if (cmp > 0)
{
++it2;
shift2++;
}
else
{
std::iter_swap(it1, std::prev(it1, shift1));
++it1;
std::iter_swap(it2, std::prev(it2, shift2));
++it2;
}
}
return std::make_tuple(std::prev(it1, shift1), std::prev(it2, shift2));
}
int main()
{
std::vector<foo> vec1=std::vector<foo>(7);
std::vector<foo> vec2=std::vector<foo>(4);
vec1={foo(1,1,0.),foo(1,2,0.),foo(2,1,0.),foo(2,2,0.),foo(2,3,0.),foo(3,1,0.),foo(3,2,0.)};
vec2={foo(1,2,0.),foo(1,3,0.),foo(2,1,0.),foo(3,1,0.)};
auto remove_iters = remove_difference(vec1, vec2);
vec1.erase(std::get<0>(remove_iters), vec1.end());
vec2.erase(std::get<1>(remove_iters), vec2.end());
std::cout<<"vec1:\n";
for(auto i: vec1) std::cout<<i.x<<" "<<i.y<<"\n";
std::cout<<"\nvec2:\n";
for(auto i: vec2) std::cout<<i.x<<" "<<i.y<<"\n";
return 0;
}
Output:
vec1:
1 2
2 1
3 1
vec2:
1 2
2 1
3 1
The only thing to not is that this assumes that there are no repeated coordinates, or more specifically, that they are repeated the same number of times on both vectors, and "extra" repetitions would be removed (you could adapt the algorithm to change that if you needed, although it would make the code a bit uglier).
Maybe something like this? You choose first which vector is bigger then iterate (mainly) over the bigger one and check inside the other one.
int main()
{
std::vector<foo> vec1=std::vector<foo>(7);
std::vector<foo> vec2=std::vector<foo>(4);
vec1={foo(1,1,0.),foo(1,2,0.),foo(2,1,0.),foo(2,2,0.),foo(2,3,0.),foo(3,1,0.),foo(3,2,0.)};
vec2={foo(1,2,0.),foo(1,3,0.),foo(2,1,0.),foo(3,1,0.)};
std::vector<foo>::iterator it_begin;
std::vector<foo>::iterator it_end;
std::vector<foo>* main;
std::vector<foo>* other;
if( vec1.size() > vec2.size() ) {
it_begin = vec1.begin();
it_end = vec1.end();
main = &vec1;
other = &vec2;
}
else {
it_begin = vec2.begin();
it_end = vec2.end();
main = &vec2;
other = &vec1;
}
std::vector<foo> new_vec;
for( it_begin; it_begin != it_end; ++it_begin ) {
auto cur_element = *it_begin;
auto intersec = std::find_if( other->begin(),other->end(),[cur_element]
(foo & comp_element)->bool{
return( (cur_element.x==comp_element.x ) && ( cur_element.y==comp_element.y ) );
});
if( intersec != other->end() )
{
new_vec.push_back( cur_element );
}
}
vec1 = new_vec;
vec2 = new_vec;
std::cout<<"vec1:\n";
for(auto i: vec1) std::cout<<i.x<<" "<<i.y<<"\n";
std::cout<<"\nvec2:\n";
for(auto i: vec2) std::cout<<i.x<<" "<<i.y<<"\n";
return 0;
}

Why am I getting errors in the following function? [duplicate]

I have a vector of Student which has a field name.
I want to iterate over the vector.
void print(const vector<Student>& students)
{
vector<Student>::iterator it;
for(it = students.begin(); it < students.end(); it++)
{
cout << it->name << endl;
}
}
This is apparently illegal in C++.
Please help.
You have two (three in C++11) options: const_iterators and indexes (+ "range-for" in C++11)
void func(const std::vector<type>& vec) {
std::vector<type>::const_iterator iter;
for (iter = vec.begin(); iter != vec.end(); ++iter)
// do something with *iter
/* or
for (size_t index = 0; index != vec.size(); ++index)
// do something with vec[index]
// as of C++11
for (const auto& item: vec)
// do something with item
*/
}
You should prefer using != instead of < with iterators - the latter does not work with all iterators, the former will. With the former you can even make the code more generic (so that you could even change the container type without touching the loop)
template<typename Container>
void func(const Container& container) {
typename Container::const_iterator iter;
for (iter = container.begin(); iter != container.end(); ++iter)
// work with *iter
}
Use const_iterator instead. An iterator allows modification of the vector, so you can't get one from a const container.
Also, the idiomatic way to write this loop uses it != students.end() instead of < (though this should work on a vector).
C++11 style:
void print(const vector<Student>& students) {
for(auto const& student : students) {
cout << student.name << endl;
}
}
Instead of vector<Student>::iterator, use vector<Student>::const_iterator.
void print(const vector<Student>& students)
{
vector<Student>::const_iterator it; // const_iterator
for(it = students.begin(); it != students.end(); it++)
{
cout << it->name << endl;
}
}
void print(const vector<Student>& students)
{
for(auto it = students.begin(); it != students.end(); ++it)
{
cout << it->name << endl;
}
}

Getting vectors representing subsets of a map

I would like to get vectors representing each possible subset of specific length of consecutive elements of a map, per the inherent ordering, for example:
How can this be done?
You may iterate iver the map as key are ordered:
std::vector<std::array<Sample, 3u>> get_triplets(const std::map<int, Sample>& samples)
{
if (samples.size() < 3) {
return {};
}
std::vector<std::array<Sample, 3u>> res;
auto it = samples.begin();
auto it1 = std::next(it);
auto it2 = std::next(it1);
for (; it2 != samples.end(); ++it, ++it1, ++it2) {
res.push_back({{it->second, it1->second, it2->second}});
}
return res;
}
Live Demo
Edit: to have n-uplets, small changes from previous triplet version:
std::vector<std::vector<Sample>> get_n_uplets(std::size_t n, const std::map<int, Sample>& samples)
{
if (samples.size() < n) {
return {};
}
std::vector<std::vector<Sample>> res;
auto first = samples.begin();
auto last = std::next(first, n - 1);
for (; last != samples.end(); ++first, ++last) {
std::vector<Sample> inner;
for (auto it = first; it != std::next(last); ++it) {
inner.push_back(it->second);
}
res.push_back(inner);
}
return res;
}
Live Demo

Why do I get a segmentation fault while iterating through this vector?

I need to go through this vector and delete the duplicates. A segmentation fault is occurring somewhere within this code. My guess is that it has something to do with deleting elements while the iterator is going through, but I don't really have a concrete understanding of how these iterators are actually working yet, so I can't figure it out.
vector<char *>::iterator iter;
for (iter = v->begin(); iter != v->end()-1; iter++ ){
char *aString = *iter;
int n = 1;
while(iter+n != v->end()){
int comparison = strcmp(aString, *(iter+n));
if(comparison == 0){
v->erase(iter + n);
}
n++;
}
}
Really, you just have a couple off-by-one problems here. You were comparing incorrectly against end() and incrementing n when you erased an element:
for (iter = v->begin(); iter != v->end()-1; iter++ ){
^^^^^^^^
And
while(iter+n != v->end())
^^
The following will do what you want (and demonstrate that it works):
int main()
{
std::vector<const char*> v (4, "this");
std::vector<const char *>::iterator iter;
for (iter = v.begin(); iter < v.end(); iter++ ) {
std::cout << *iter << " ";
}
std::cout << std::endl;
for (iter = v.begin(); iter < v.end(); iter++ ){
const char *aString = *iter;
int n = 1;
while(iter+n < v.end()){
int comparison = strcmp(aString, *(iter+n));
if(comparison == 0){
v.erase(iter + n);
}
else
n++;
}
}
for (iter = v.begin(); iter < v.end(); iter++ ) {
std::cout << *iter << std::endl;
}
}
Output is:
this this this this
this
You are not properly iterating through the remainder of the vector. An alternative to what Beta suggested is to use erase-remove with remove_if. Like this:
bool compare_strings(char * aString,char * bString)
{
return 0==strcmp(aString,bString);
}
void remove_duplicates(vector<char *> * v)
{
vector<char *>::iterator iter;
for (iter = v->begin(); iter != v->end(); iter++ ) {
v->erase(std::remove_if(iter+1,v->end(),compare_strings),v->end());
}
}
When you erase an element from the vector, the vector gets one element shorter. Try this:
if(comparison == 0){
v->erase(iter + n);
}
else{
n++;
}
Erasing from a vector invalidates all iterators from the erasee onwards, so you should probably not construct your loop the way you do, and rather use a standard idiom like this:
for (auto it = v.begin(); it != v.end(); ++it) // no end() - 1 -- may not be legal!
{
for (auto jt = it; jt != v.end(); )
{
if (jt == it) continue;
if (strcmp(*it, *jt) == 0)
{
jt = v.erase(jt);
}
else
{
++jt;
}
}
}
This code avoids the check for an empty vector, which your code fails to account for.

How do I iterate over a Constant Vector?

I have a vector of Student which has a field name.
I want to iterate over the vector.
void print(const vector<Student>& students)
{
vector<Student>::iterator it;
for(it = students.begin(); it < students.end(); it++)
{
cout << it->name << endl;
}
}
This is apparently illegal in C++.
Please help.
You have two (three in C++11) options: const_iterators and indexes (+ "range-for" in C++11)
void func(const std::vector<type>& vec) {
std::vector<type>::const_iterator iter;
for (iter = vec.begin(); iter != vec.end(); ++iter)
// do something with *iter
/* or
for (size_t index = 0; index != vec.size(); ++index)
// do something with vec[index]
// as of C++11
for (const auto& item: vec)
// do something with item
*/
}
You should prefer using != instead of < with iterators - the latter does not work with all iterators, the former will. With the former you can even make the code more generic (so that you could even change the container type without touching the loop)
template<typename Container>
void func(const Container& container) {
typename Container::const_iterator iter;
for (iter = container.begin(); iter != container.end(); ++iter)
// work with *iter
}
Use const_iterator instead. An iterator allows modification of the vector, so you can't get one from a const container.
Also, the idiomatic way to write this loop uses it != students.end() instead of < (though this should work on a vector).
C++11 style:
void print(const vector<Student>& students) {
for(auto const& student : students) {
cout << student.name << endl;
}
}
Instead of vector<Student>::iterator, use vector<Student>::const_iterator.
void print(const vector<Student>& students)
{
vector<Student>::const_iterator it; // const_iterator
for(it = students.begin(); it != students.end(); it++)
{
cout << it->name << endl;
}
}
void print(const vector<Student>& students)
{
for(auto it = students.begin(); it != students.end(); ++it)
{
cout << it->name << endl;
}
}