KaiserJohaan
KaiserJohaan

Reputation: 9240

Iterator for a subset of a vector

Is it possible to get a const iterator from a vector that can only iterate a certain range of the vector before being invalidated?

For example if I have a vector of 10 elements, I want to return an iterator of elements 4 to 7.

pseudo-code:

int main()
{
    std::vector<int> vector = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };

    auto iterator = GetRangedIterator(vector, 4, 7)
    for (const int& num : iterator)
        print num;      // 4, 5, 6, 7
}

Upvotes: 14

Views: 8834

Answers (5)

TemplateRex
TemplateRex

Reputation: 70526

You could use the range-v3 library that is the bases of a Ranges TS which will been part of C++20, but the library already works with C++11 compilers. Here's how:

#include <range/v3/all.hpp>
#include <iostream>
#include <vector>

int main() 
{
    using namespace ranges;

    auto v = view::iota(1, 11) | to_<std::vector<int>>();
    std::cout << view::all(v)  << '\n';

    auto rng = v | view::slice(3, 7); 
    std::cout << rng << '\n';
}

Live Example.

Upvotes: 6

einpoklum
einpoklum

Reputation: 131626

You can use a span:

auto first_index = 3;
auto last_index = 6;
auto count = last_index - first_index + 1;
auto interesting_nums = gsl::make_span(std::cbegin(vector) + start_index, count);
for(auto& num : interesting_nums) { /* do stuff */ }

Notes:

  • In your example you got the 4th through the 7th element, i.e. indices 3 through 6 which is what I used here.
  • This piece of code should work for about any container, not just a vector.
  • spans are part of the GSL, support library for the C++ Core Guidelines. They may enter the C++ standard officially in 2020 and are viewed quite favorably by the community.

Upvotes: 0

Rafayel Paremuzyan
Rafayel Paremuzyan

Reputation: 147

You can use this

for( it = v1.begin() + a; it <= v1.begin() + b; it++ )

The code below is a small demonstration

#include <vector>
#include <iostream>

using namespace std;

int main(){

  vector<int> v1;

  for( int i = 0; i < 50; i++ ){
    v1.push_back( 2*(i+1) );
    cout<<v1.at(i)<<"   ";
  }
  cout<<endl;


  vector<int>::iterator it;

  int a = 5;
  int b = 9;

  for( it = v1.begin() + a; it <= v1.begin() + b; it++ ){

    cout<<(*it)<<"   ";
  }
  cout<<endl; 
}

The output is

2   4   6   8   10   12   14   16   18   20   22   24   26   28   30   32   34   36   38   40   42   44   46   48   50   52   54   56   58   60   62   64   66   68   70   72   74   76   78   80   82   84   86   88   90   92   94   96   98   100   
12   14   16   18   20   

Upvotes: 4

Jerry Coffin
Jerry Coffin

Reputation: 490158

This is pretty trivial to do (though I'd call the result a range, not an iterator).

A simple implementation would look something like this:

template <class Iter>
class range {
    Iter b;
    Iter e;
public:

    range(Iter b, Iter e) : b(b), e(e) {}

    Iter begin() { return b; }
    Iter end() { return e; }
};

template <class Container>
range<typename Container::iterator> 
make_range(Container& c, size_t b, size_t e) {
    return range<typename Container::iterator> (c.begin()+b, c.begin()+e);
}

As it stands right now, this follows normal C++ conventions (0-based counting, the end you specify is past the end of the range, not in it) so to get the output you asked for, you'd specify a range of 3, 7, like:

for (int num : make_range(vector, 3, 7))
    std::cout << num << ", ";      // 4, 5, 6, 7,

Note that the range-based for loop knows how to use begin and end member functions to tell it the range it's going to iterate, so we don't have to deal with invalidating iterators or anything like that, we just have to specify the beginning and end of the range we care about.

Upvotes: 20

Baldrick
Baldrick

Reputation: 11840

There's nothing in the standard library to explicitly do this, but if you're willing to use Boost, you can use the following approach using the range concept:

auto range = boost::make_iterator_range(v.begin()+3, v.begin()+7);

BOOST_FOREACH(int i, range)
{
    cout << i << endl;
}

This should output 4567

Upvotes: 2

Related Questions