cateof
cateof

Reputation: 6758

iterate an STL container not from the .begin()ing and wrap around

I have an std::vector, let's say of integers for simplicity.

std::vector<int> ivec;
ivec.push_back(1);
ivec.push_back(2);
... //omitting some push back's 3 to 99
ivec.push_back(100);

The standard way to iterate is known

std::map<int>::iterator it;
for( it = ivec.begin(); it != ivec.end(); it++ ) 
  print();

That iteration will print 1,2,3, ... 100.

I want to traverse all vector elements starting from a predefined index and not from it.begin(). I would like to print

3,4,5,6 ... 99, 100, 1, 2

Can you share your thoughts here?

It might ok to do it in two steps

for( it = ivec.begin()+index; it != ivec.end(); it++ ) and then (if index !=0)

for ( it = ivec.begin; it = it = ivec.begin() + (index-1); it++)

Upvotes: 10

Views: 6081

Answers (6)

jpihl
jpihl

Reputation: 8071

I know this is a pretty old question, but nobody mentioned std::rotate, which I think, in some cases, can be the right tool for the job.

Modified example from http://www.cplusplus.com/reference/algorithm/rotate/:

#include <iostream>     // std::cout
#include <algorithm>    // std::rotate
#include <vector>       // std::vector

int main () {
  std::vector<int> myvector;

  // set some values:
  for (int i = 1; i < 10; ++i) myvector.push_back(i); // 1, 2, 3, ... 9

  std::rotate(myvector.begin(), myvector.begin() + 2, myvector.end());
                                                  // 3, 4, 5, 6 ... 9, 1, 2
  // print out content:
  std::cout << "myvector contains:";
  for (auto it = myvector.begin(); it != myvector.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}

cpp.sh/3rdru

Output:

myvector contains: 3 4 5 6 7 8 9 1 2

Note, since my_vector is modified by the std::rotate function, this is neither very efficient nor useful if you just want to iterate the vector once.

However, while this is probably not the best answer to this SO question, I hope it can still provide some value for people with similar issues.

Upvotes: 3

jrok
jrok

Reputation: 55395

bool wrapped = false;
for (auto it = vec.begin() + index; (it != vec.begin() + index) || !wrapped; ++it)
{
    if (it == vec.end())
    {
        it = vec.begin();
        wrapped = true;
    }
    std::cout << *it;
}

Upvotes: 3

edA-qa mort-ora-y
edA-qa mort-ora-y

Reputation: 31861

I'll assume that you already have a starting iterator. How you get this depends on whether you are using an indexable (vector) type or a forward iterator only, or a keyed type. Then you can do a loop something like this:

type::iterator start_iter = /* something from collection, perhaps begin()+index */
type::iterator cur_iter = start_iter;
do
{
  //do something with cur_iter

  ++cur_iter;
  if( cur_iter == collection.end() )
    cur_iter = collection.begin();
} while( cur_iter != start_iter );

That's the basic loop.

Upvotes: 4

Filip Ros&#233;en
Filip Ros&#233;en

Reputation: 63797

A solution when using a random-access container is very simple, see the code below.

std::vector<int> v ({1,3,4,5,6,7,8,9,10}); /* c++11 */

...

for (int i = 2; i < (10+2); ++i)
  std::cout << v[i % 10] << " ";

Method when using containers only having bidirectional/forward iterators:

  std::list<int> l ({1,3,4,5,6,7,8,9,10}); /* c++11 */

  Iter start = l.begin ();
  std::advance (start, 4);

  ...

  Iter it = start;

  do {
    std::cerr << *it << std::endl;

  } while (
    (it = ++it == l.end () ? l.begin () : it) != start
  );

Upvotes: 2

PlasmaHH
PlasmaHH

Reputation: 16046

There are endless ways to do it, and probably all are (more or less) equivalent, so in the end it depends on personal preference and maybe coding style conventions. I would probably do it like:

std::cout << v[idx] << "\n";
for( auto it = v.begin() + idx + 1; it != v.begin()+idx; ++it )
{
    if( it == v.end() ) it = v.begin();
    std::cout << *it << "\n";
}

Upvotes: 0

Emilio Garavaglia
Emilio Garavaglia

Reputation: 20730

You can either:

  • develop an iterator class that wraps the vector::iterator and expose the behaviour you like (in particular: ++ checks for end() and replace it with begin() and adjust the other "border values")

  • fill the vector starting from 3 and wrap at 100, so that standard iteration will look as you want.

The choice depends on what else the vector is purposed and what else that iteration is needed.

Upvotes: 7

Related Questions