Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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
}
like image 367
KaiserJohaan Avatar asked May 29 '15 22:05

KaiserJohaan


People also ask

How do you iterate through a set of vectors?

Use a for loop and reference pointer In C++ , vectors can be indexed with []operator , similar to arrays. To iterate through the vector, run a for loop from i = 0 to i = vec. size() .

What is an iterator in vector?

Vector's iterators are random access iterators which means they look and feel like plain pointers. You can access the nth element by adding n to the iterator returned from the container's begin() method, or you can use operator [] . std::vector<int> vec(10); std::vector<int>::iterator it = vec.

Can you pass an iterator reference?

In general: If you pass a non- const reference, the caller doesn't know if the iterator is being modified. You could pass a const reference, but usually iterators are small enough that it gives no advantage over passing by value.


2 Answers

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.

like image 87
Jerry Coffin Avatar answered Oct 03 '22 04:10

Jerry Coffin


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.

like image 21
TemplateRex Avatar answered Oct 03 '22 03:10

TemplateRex