Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using auto (for iterating) in nested range-based for loop

Currently I have started using auto keyword.I have some doubt regarding that:

If I need to traverse the vector I do :

vector<int>v; 

for(auto it : v){    

   cout << it <<endl; 

}

But suppose if I need to do something like:

vector<int>v;

for(auto it:v){    
   for(auto jt:X){

   //where X is next position of it's position
   //What I mean is if it is currently at 2nd position then 
   //jt iterator will start from 3rd position

   }    
}

I have absolutely no idea how to do that.Please Suggest what is the appropriate method for that.Thanks in advance.

like image 895
bhanu Avatar asked Oct 25 '15 18:10

bhanu


Video Answer


2 Answers

auto it:v

is shorthand for...

auto it = v.begin(); it != v.end(); it++

so to use auto inside nested for loops, the longer version is more appropriate...

#include <iostream>
#include <vector>

using namespace std;

int main()
{
    vector<int> v(10, 17);
    for (auto& it = v.begin(); it != v.end(); ++it) {
        for (auto& it2 = it + 1; it2 != v.end(); ++it2) {
            cout << *it2 << " ";
        }
        cout << endl;
    }

    // system("pause");
    return 0;
}
like image 31
dspfnder Avatar answered Sep 26 '22 15:09

dspfnder


I assume that you want to use auto and the new range-based for loop.

You can create a vector_view and iterate over the "sub vector" in the inner loop.

Here's a simple example to get you started (notice the use of auto& and not auto):

Run It Online

#include <iostream>
#include <cstddef>
#include <numeric>
#include <vector>
using std::cout;
using std::endl;

template <typename T, typename A>
struct vector_view
{
    using vector_type    = std::vector<T, A>;
    using const_iterator = typename vector_type::const_iterator;
    using       iterator = typename vector_type::iterator;

    vector_type& vec;
    size_t       _begin;
    size_t       _length;

    vector_view(vector_type& v, size_t begin_, size_t length_)
    : vec(v), _begin(begin_), _length(length_) {}

    const_iterator begin() const { return vec.begin() + _begin; }
    iterator       begin()       { return vec.begin() + _begin; }

    const_iterator end()   const { return vec.begin() + _begin + _length; }
    iterator       end()         { return vec.begin() + _begin + _length; }
};

int main()
{
    std::vector<int> v(10);
    std::iota(v.begin(), v.end(), 0);

    for (auto& it : v)
    {
        size_t begin  = std::distance(&v[0], &it) + 1;
        size_t length = v.size() - begin;
        vector_view<typename decltype(v)::value_type,
                    typename decltype(v)::allocator_type
        > vv(v, begin, length);

        cout << it << ": ";
        for (auto& jt : vv)
        {
            cout << jt << " ";
        }
        cout << endl;
    }
}

Output:

0: 1 2 3 4 5 6 7 8 9 
1: 2 3 4 5 6 7 8 9 
2: 3 4 5 6 7 8 9 
3: 4 5 6 7 8 9 
4: 5 6 7 8 9 
5: 6 7 8 9 
6: 7 8 9 
7: 8 9 
8: 9 
9: 

EDIT: You can make the syntax less verbose if you define a make_vector_view() function:

template <typename T, typename A>
vector_view<T, A> make_vector_view(std::vector<T, A>& v,
                                   size_t             begin_,
                                   size_t             length_)
{
    return {v, begin_, length_};
}

And thanks to template argument type deduction, you can write:

Run It Online

for (auto& it : v)
{
    size_t begin  = std::distance(&v[0], &it) + 1;
    size_t length = v.size() - begin;

    cout << it << ": ";
    for (auto& jt : make_vector_view(v, begin, length))
    {
        cout << jt << " ";
    }
    cout << endl;
}
like image 87
maddouri Avatar answered Sep 23 '22 15:09

maddouri