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++)
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.
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.
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;
}
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.
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
);
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";
}
Related
This question already has answers here:
Appending to a vector while iterating over it?
(8 answers)
Closed 15 days ago.
I want to loop a increasing container, for example, if the container is std::vector. i need to push_back when looping the vector elements.
std::vector<int> v = {1, 3,5, 7,9};
for (auto i : v) { // v is std::vector
if (i % 2 == 1) v.push_back(i + 1); // just a demo, the push_back will happen in some condition, won't be a endless loop
printf("%d ", i);
} // the expected result is : 1, 3, 5, 7, 9, 2, 4, 6, 8, 10
I know vector is not the correct container, is there any good tools can handle this?
The problem is, as 463035818_is_not_a_number said in the comments, push_back() can (potentially) invalidates iterators. (for example, it can make std::vector to re-reallocate).
A much simpler solution is to use a for loop instead:
int main()
{
std::vector<int> v = {1, 3,5, 7,9};
for (int i = 0; i < v.size(); ++i)
{
if (v[i] % 2 == 1)
{
v.push_back(v[i] + 1);
}
std::cout << v[i] << ' ';
}
}
Link.
You can't use iterators or a range based for loop because of reallocation. But there's nothing wrong with the old-school approach of using an index. That's immune to reallocation
std::vector<int> v = {1, 3, 5, 7, 9};
for (size_t i = 0; i < v.size(); ++i) {
if (v[i] % 2 == 1)
v.push_back(v[i] + 1);
printf("%d ", v[i]);
}
push_back invalidates iterators when the vector has to reallocate. You can resevere enough space and use an iterator based loop:
#include <vector>
#include <iostream>
int main() {
std::vector<int> v = {1, 3,5, 7,9};
v.reserve(v.size()*2);
auto begin = v.begin();
auto end = v.end();
for (; begin != end; ++begin) {
if (*begin % 2 ==1) v.push_back(*begin + 1);
}
for (const auto& e : v) std::cout << e << " ";
}
This assumes that you only need to iterate the elements that were already in the vector before the loop. (Your code assumes that the loop iterates also the newly added ones, but the condition is such that this is not necessary. You need a second loop for printing then.)
Alternatively you could use an index based loop:
auto s = v.size();
for (size_t i=0; i < s; ++i) {
// ....
I have a below program. I need to understand why do we need to decrement pointer when we use erase method?
Also is there any better way which does not create a such confusion ?
#include <iostream>
#include <vector>
using namespace std;
int main()
{
vector<int> myvector{ 1, 2, 3, 4, 5, 6, 7, 8, 9 };
for (auto i = myvector.begin(); i != myvector.end(); ++i) {
if (*i % 2 == 0) {
myvector.erase(i);
i--;// why do we need to decrement ?
}
}
// Printing the vector
for (auto it = myvector.begin(); it != myvector.end(); ++it)
cout << ' ' << *it;
return 0;
}
I need to understand why do we need to decrement pointer when we use erase method?
You don't, and shouldn't. The correct thing to do is use the return value of erase. At the moment your program has undefined behaviour because you are modifying an invalid iterator.
for (auto i = myvector.begin(); i != myvector.end();) {
if (*i % 2 == 0) {
i = myvector.erase(i);
} else {
++i;
}
}
Also is there any better way which does not create a such confusion ?
Yes, std::remove_if
auto is_even = [](int i){ return (i % 2) == 0; };
auto last = std::remove_if(myvector.begin(), myvector.end(), is_even);
myvector.erase(last, myvector.end());
You have a good answer from Caleth, but I'm going to add some information:
for (auto i = myvector.begin(); i != myvector.end(); ++i) {
if (*i % 2 == 0) {
myvector.erase(i);
i--;// why do we need to decrement ?
}
}
That's your code. For my explanation, let's believe that the iterator is just an index (an int). It's not, but it works for understanding.
Let's say myvector contains the integers 0..10 and you delete 4. Once you do:
0 1 2 3 5 6 7 8 9 10
Now, imagine your loop. You get to the bottom of the for-loop and increment i -- it now has 5, but you skip over checking if the old myvector[5] -- which is now stored in myvector[4] -- fits your if-statement.
The other way to write this:
for (auto i = myvector.begin(); i != myvector.end(); ) {
if (...) ...
else {
++i;
}
}
That is, you only increment the iterator if you do NOT delete. This avoids skipping over the item after the one you deleted (because it moved into the deleted guy's spot).
However, this is the wrong way to do it, and Caleth has better answers for how to do it properly.
Is there a better way of finding elements of a std::list that have the same value as manually going over the sorted list and comparing each element like this:
for(auto it = l.begin(); it != l.end(); it++) {
auto nextElement = it;
nextElement++;
if(nextElement == l.end())
break;
if(*it == *nextElement)
cout << "Equal" << endl;
}
There is actually a really nice and compact way to get a list of all of the duplicates in a set of data, whether it is sorted or not. What we can do is leverage std::map/std::unordered_map and use the elements value as the key for the map, and make the value a count of the number of times that value was "inserted". That would look like
std::unordered_map<int, int> histogram;
for (auto e : l)
++histogram[e]; // gets a count of the number of duplicates
and then all you need to do is iterate the map and check for entries that have a mapped value greater than 1. That would look like
for (const auto& pair : histogram)
if (pair.second > 1)
std::cout << "value: " << pair.first << " has " << pair.second << " matches.\n";
Using a std::map this is O(NlogN + M) and using an unoredered_map this is O(N + M) where N is the size of l and M is the size of histogram.
Use the STL algorithm adjacent_find:
auto it = l.begin()
while((it = std::adjacent_find(it, l.end())) != l.end()){
std::cout << "Equal\n";
++it;
}
Since you say the list is sorted, then std::adjacent_find will detect whether there are duplicates:
#include <algorithm>
if (std::adjacent_find(l.begin(), l.end()) != l.end()) {
// we have at least one duplicate
}
If you wish to do something with all the duplicates, then we can loop over the pairs:
for (auto it = std::adjacent_find(l.begin(), l.end());
it != l.end();
it = std::adjacent_find(std::next(it), l.end())
{
// *it and *std::next are duplicates (and there may be more)
}
It's possible that we want to find and process all of each group of identical elements together:
auto begin = std::adjacent_find(l.begin(), l.end());
while (begin != l.end()) {
auto end = std::find_if_not(begin, l.end(),
[begin](auto n){ return n == *begin;});
// All elements from begin (inclusive) to end (exclusive) are equal.
// Process them here.
begin = std::adjacent_find(end, l.end());
}
Is there a clean way to check if I am currently at the second to last element in an iteration in C++? As in:
for (vector::iterator it = v.begin(); it < v.end(); ++it)
{
if (it points to second to last element)
cout << "at second to last";
}
The easiest way would be to compare your iterator against one which does indeed point to the second-to-last. And an easy way to get that is:
vector::iterator secondLast = v.end() - 2;
Assuming of course that v.size() >= 2. But the above doesn't generalize to other container types, for which you could do this:
vector::iterator secondLast = (++v.rbegin()).base();
This should rewind from the last element one step, then convert to a regular (forward) iterator. This will work with other container types like lists.
Or perhaps clearer for the general solution:
vector::iterator secondLast = v.end();
std::advance(secondLast, -2);
Again this requires size of 2 and iterators of random access or bidirectional type.
And finally, a C++11 solution:
auto secondLast = std::prev(v.end(), 2);
Try something like this:
vector::iterator end = v.end(), stl;
bool has_stl = (v.size() >= 2);
if (has_stl) stl = end-2;
for (vector::iterator it = v.begin(); it < end; ++it)
{
if ((has_stl) && (it == stl))
cout << "at second to last";
}
You can do this with some containers:
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec {1, 2, 3, 4, 5};
for (auto it = vec.begin(); it != vec.end(); it++) {
if (vec.end() - it == 3) {
std::cout << *it << std::endl;
}
}
return 0;
}
A solution below:
auto pos = std::next(std::begin(v), std::distance(std::begin(v), std::end(v))-2);
for (auto it = std::begin(v); it != std::end(v); ++it)
{
if (it == pos)
cout << "at second to last: " << *pos;
}
pos is now an iterator pointing to the second to last position, and the functions std::next and std::distance use the best implementation possible (i.e. constant complexity for random iterators, linear complexity for bidirectional/forward iterators).
I have a set of ints set something; of length 52.
I am using cycles to iterate through the set like this:
for(iterator A from 1st to 48th element)
for(iterator B from A+1 to 49th element)
for(iterator C from B+1 to 50th element)
for(iterator D from C+1 to 51th element)
for(iterator E from D+1 to 52th element)
{
//save the values from the actual positions in set in array[5]
}
First I tried to make it with an iterator but then I realised that it's not possible to start an iterator from the position of another iterator +1.
Then I tried to use pointers and jump through the values but I correctly assigned only the first value and then I can't jump on second etc.
My code was:
set<int> tableAll;
for(int i=4; i!=52; ++i)
tableAll.insert(i);
const int * flop1 = & * tableAll.begin();
cout << * flop1 << endl;
flop1++;
cout << * flop1 << endl;
When I cout the value of pointer flop1, I get 4 and that's ok, but when I increase it and again cout on screen, I get 0, then, 49, then 0, then 1, then 0 instead 5, 6, 7, 8 and 9.
So how to iterate through my set correctly? I assume using pointers will be faster then some iterator solution.
You absolutely can iterate from an offset from another iterator:
for (auto a(std::begin(mySet)), a_end(std::prev(std::end(mySet), 4));
a != a_end; ++a)
for (auto b(std::next(a)), b_end(std::next(a_end); b != b_end; ++b)
...
In C++03, you can write next and begin for compatibility:
template<typename Iterator> Iterator next(Iterator it, int n = 1) {
std::advance(it, n);
return it;
}
template<typename Iterator> Iterator prev(Iterator it, int n = 1) {
std::advance(it, -n);
return it;
}
for (std::set<int>::const_iterator a(mySet.begin()),
a_end(std::prev(mySet.end(), 4)); a != a_end; ++a)
for (std::set<int>::const_iterator b(std::next(a)),
b_end(std::next(a_end)); b != b_end; ++b)
...
This code is not optimal as it do unneeded iterator comparisions, but works and is simply:
set<int> tableAll;
for(int i=0; i!=52; ++i)
tableAll.insert(i);
for( set<int>::iterator iA=tableAll.begin(); iA != tableAll.end(); ++iA )
for( set<int>::iterator iB=iA; ++iB != tableAll.end(); )
for( set<int>::iterator iC=iB; ++iC != tableAll.end(); )
for( set<int>::iterator iD=iC; ++iD != tableAll.end(); )
for( set<int>::iterator iE=iD; ++iE != tableAll.end(); )
{
cout<<*iA<<' '<<*iB<<' '<<*iC<<' '<<*iD<<' '<<*iE<<endl;
}
I'd suggest to copy the set to a temporary std::vector.
All operations you do in the loops are natural for a vector and O(1) (except for the loops themselves of course)
That's easier to read, to write, and should run a lot faster.