c++ list iterator arithmetic replacement ideas - c++

I have a list that gets accessed in multiple places. There are some cases where I need to loop through the list from beginning to (end-n) elements and others where the whole list is accessed. I'm having trouble with the iterator arithmetic.
I want something that could do the following:
int n =10;
for (list<Term>::iterator itr = final.begin(); itr != (final.end()-n); itr++) {
//
}
does the following pseudo code make sense?
int N = myList.size() - n;
for (list<Term>::iterator itr = final.begin(),int length_reached=0; itr != (final.end() && length_reached<N; itr++,length_reached++) {
//
}
Using rbegin for me is not an option since I want the first instance of a match from the start of the list.
is there a better way of implementation here?

Since it's a list, random access is slow. Fortunately for you:
you're always starting at the beginning, and
std::list has a size() method
here's one way:
list<Term>::iterator itr = final.begin();
int to_do = std::max(0, int(final.size()) - n);
for ( ; to_do ; --to_do, ++itr )
{
// code here
}

Yes you can do this way
if ( n < final.size() )
{
auto m = final.size() - n;
for ( auto first = final.begin(); m != 0; ++first, --m )
{
//...
}
}
If the iterator itself can be changed in the loop then you can write the loop condition the following way
if ( n < final.size() )
{
auto m = final.size() - n;
for ( auto first = final.begin(); m != 0 && first != final.end(); ++first, --m )
{
//...
}
}

you can use reverse iterator and the std::advance
auto rit =final.rbegin();
std::advance(rit, n);
for (auto itr=final.begin(); itr!=rti.base(); ++itr) {
}

Related

How to use erase() function to erase a vector by indexing?

To traverse a vector array normally, I use indexing(see code) instead of using an iterator. Today, I have tried to erase a vector element by indexing. I have tried several times and several ways, but each time there seems to be an error in the last line(in the compiler).
Please help me fix the code to erase an element by indexing. Thanks in advance.
vector<pair<int, pair<int, int> > > p;
p.push_back(make_pair(1,make_pair(2,4))) ;
p.push_back(make_pair(5,make_pair(6,7))) ;
for(int i = 0; i != p.size(); i++)
if(p[i].first == 1)
p.erase(i);
You can use
for(int i = 0; i != p.size(); ) // Don't increment here.
{
if(p[i].first == 1)
{
p.erase(p.begin() + i );
}
else
{
++i;
}
}
but it will be more idiomatic to use:
for ( auto iter = p.begin(); iter != p.end(); )
{
if( iter->first == 1 )
{
iter = p.erase(iter);
}
else
{
++iter;
}
}
Better still, use the erase-remove idiom.
p.erase(std::remove_if(p.begin(), p.end(),
[](std::pair<int, std::pair<int, int>> const& item) { return item.first == 1;}),
v.end());
It is not starightforward to make your code work as your indexing with i will be broken when you erase element - you need to increase i only when element is not erased.
for(int i = 0; i != p.size(); )
if(p[i].first == 1)
p.erase(p.begin() + i);
else
i++;
but you better use erase-remove idiom, as it is less error prone and more efficient (erasing in middle of vector is quite expensive):
p.erase( std::remove_if( p.begin(), p.end(), []( const auto &pair ) { return pair.first == 1; } ), p.end() );
std::remove_if()

how to sort vector of a structure without C++ STL sort()

I'm trying to sort a vector, which contain a structure. In this program i do't want to use any C++ Standard Template Library (STL) such as sort().
I tried this code
for (auto k = GTSlist.begin(); k != GTSlist.end(); k++)
{
for (auto l = GTSlist.begin()+1; l != GTSlist.end(); l++)
{
if(k->owner > l->owner)
{
auto tmp = k->owner;
k->owner = l->owner;
l->owner = tmp;
}
}
}
Print vector value
for (auto k = GTSlist.begin(); k != GTSlist.end(); k++)
{
cout << "\n print sorted vector k->owner =" << k->owner << "k->length =" << k->length ;
}
Declaration of structure
Struct Basic802154GTSspec
{
int owner;
int start;
int length;
}
Declaration of structure
vector <Basic802154GTSspec> GTSlist;
Inserting value in vector
// GTSlist.end()=5,length = 1,2,3,4,5 , owner= 5,1,4,2,3
for (auto k = GTSlist.begin(); k != GTSlist.end(); k++) {
Basic802154GTSspec newGTSspec;
newGTSspec.length = value shown above;
newGTSspec.owner = value shown above;
GTSlist.push_back(newGTSspec);
}
Expected result
print sorted vector k->owner k->length= 1,2; 2,4; 3,5; 4,3; 5,1
Actual result
print sorted vector k->owner k->length= 1,1; 5,2; 2,3; 4,4; 3,5
This code is wrong:
if(k->owner > l->owner)
{
auto tmp = k->owner;
k->owner = l->owner;
l->owner = tmp;
}
Do this instead:
if (k->owner > l->owner)
{
auto tmp = *k;
*k = *l;
*l = tmp;
}
And, because I think auto obscures an important detail here:
if (k->owner > l->owner)
{
Basic802154GTSspec tmp = *k;
*k = *l;
*l = tmp;
}
And, lastly, you should investigate using ::std::iter_swap as the other answer suggested. This is an STL convenience function and a companion to ::std::swap (which you could've also used here). The chief advantages you'd get with it is that you'd simplify your code slightly which removes chances for error, and that it would use move semantics where it could, which would be more efficient in many cases (though likely not your specific case).
If you don't know what move semantics are, don't worry about it right now. It's an intermediate to advanced C++ idea that you can skip worrying about as a beginner.
All that being said, it is foolish not to use the STL algorithms. Your sort implementation is the second worse sorting algorithm (bubble sort) I know. The only one that I know of that is worse is one that repeatedly shuffles the array until it by chance ends up in sorted order.
You probably want to user iter_swap instead, and your function becomes extremely simpel:
template <typename ForwardIterator>
void bubble_sort( ForwardIterator first, ForwardIterator last )
{
for ( ForwardIterator sorted = first; first != last; last = sorted )
{
sorted = first;
for ( ForwardIterator current = first, prev = first; ++current != last; ++prev )
{
if ( *current < *prev )
{
std::iter_swap( current, prev );
sorted = current;
}
}
}
}
In
for (auto k = GTSlist.begin(); k != GTSlist.end(); k++)
{
for (auto l = GTSlist.begin()+1; l != GTSlist.end(); l++)
{
if(k->owner > l->owner)
{
auto tmp = k->owner;
k->owner = l->owner;
l->owner = tmp;
}
}
}
you only exchange 'owner' while you need to exchange all the struct content, and also l does not depend on k, do (I suppose you do not want to use std::swap too)
for (vector <Basic802154GTSspec>::iterator k = GTSlist.begin(); k != GTSlist.end(); k++)
{
for (vector <Basic802154GTSspec>::iterator l = k+1; l != GTSlist.end(); l++)
{
if(k->owner > l->owner)
{
auto tmp = *k;
*k = *l
*l = tmp;
}
}
}
You also have a catastrophic problem in
for (auto k = GTSlist.begin(); k != GTSlist.end(); k++) {
Basic802154GTSspec newGTSspec;
newGTSspec.length = value shown above;
newGTSspec.owner = value shown above;
GTSlist.push_back(newGTSspec);
}
if GTSlist is not empty when you reach that for you will never stop and continuously add a new element in GTSlist

What's the difference between using Iterator and for loop for a vector

I would like to find out the difference between this code:
Vertices {
int x;
int y;
};
vector<Vertices>point;
Vertices min1,max1;
i = point.begin();
min1.y = i->y;
min1.x = i->x;
max1.x = i->x;
i++;
if(i->x < min1.x)
{
min1.x = i->x;
}
else
{
max1.x = i->x;
}
and this code:
min1.y = point[0].y;
min1.x = point[0].x;
max1.x = point[0].x;
for (int i = 1; i < point.size(); i++) {
if (point[i].x < min1.x)
min1.x = point[i].x;
else
max1.x = point[i].x;
}
EDIT
I have added in why for the 2nd piece of code to iterate from the 2nd element. What I'm doing is to compare and get the largest and smallest values. What I don't get it is why do they give me 2 different set of values? Am I misunderstanding something wrong?
First difference is that you don't have a loop in first case. It treats only very first element.
Second difference is that you start from 1 when you have a 0-th element in the second case. It treats all elements except very first.
Even with iterator you has to have a loop. The difference between using and not using iterators is just a convenience. Iterators are just different interface to access elements in a vector.
The iterator std::vector<typename>::iterator itr starts at the beginning of the vector, which is by default the first value of of your std::vector<typename> myVector.
When using a array you should start off with the very first element which is [0] not [1].
And here's a short example (out of my code) of using a iterator in a for loop:
void Rep_C_F_in_Ex (std::vector<std::string> *vTestTwo)
{
std::vector<std::string> vTestOne_;
for (std::vector<std::string>::iterator itr = vTestTwo->begin(); itr != vTestTwo->end(); itr++)
{
boost::split_regex (vTestOne_, *itr, boost::regex (",") );
for (std::vector<std::string>::iterator iterate = vTestOne_.begin(); iterate != vTestOne_.end(); iterate++)
{
vTestThree.push_back (*iterate);
++iterate;
vTestFour.push_back (*iterate);
}
}
}
If you want to loop it as array, you should start from 0 instead of 1.
int i = 0;
Bettor write it as below:
for (std::vector<xxx>::iterator it = point.begin(); it != point.end; ++it)

How to write a for loop that uses both an iterator and an index counter?

I have a function that looks like this:
void myclass::myfunc()
{
int i;
for( std::vector<Foo>::iterator it = var.begin(), i = 0; it < var.end(); it++, i++ )
{
/* ... */
}
}
I'm getting this error:
Cannot convert from int to std::_Vector_iterator<>
What is wrong with this code?
The issue is with this part of the for loop:
std::vector<Foo>::iterator it = var.begin(), i = 0
C++ is interpreting this not as two comma-separated statements, but as a variable declaration for a variable named it that's an iterator, and as a new declaration of a variable i that's an iterator and initialized to 0. The error is because you can't initialize a vector iterator to 0.
To fix this, you'll need to hoist the definition outside of the loop:
int i = 0;
std::vector<Foo>::iterator it = var.begin();
for(; it < var.end(); it++, i++ )
{
// ...
}
Or move the initialization of i outside the loop:
int i = 0;
for( std::vector<Foo>::iterator it = var.begin(); it < var.end(); it++, i++ )
{
// ...
}
Here's another option. If you need to keep track of the index into the vector you're currently looking at, you could consider just using a counting for loop (without the iterator), or using just the iterator and using iterator subtraction to recover the index:
for (auto it = var.begin(); it != var.end(); ++it) {
// current position is it - var.begin();
}
And, finally, if you have a C++20-compliant compiler, you could eliminate the iterator entirely and use an enhanced for loop in the following way:
/* Requires C++20 */
for (int i = 0; Foo f: var) {
/* Do something worthwhile with f. */
i++;
}
Hope this helps!
You can do it like this:
int i = 0;
for( std::vector<int>::iterator it = v.begin(); it < v.end(); ++it, ++i){}
Get rid of the i=0; part (at least inside the loop header).
Also, if you insist on doing this at all, consider using:
for (auto it : var)
or:
for (auto it = var.begin(); it != var.end(); ++it)
...instead. Since you're using a random access iterator anyway, what you have as i is equivalent to it - var.begin(). Conversely, you could just use:
for (int i=0; i<var.size(); i++)
...and get an iterator when needed as var.begin() + i.
Depending on what's in the body of the loop, you probably want to get rid of the loop entirely, and replace it with an algorithm though.
Double iteration:
using std::begin; using std::end;
for (auto p = std::make_pair( begin(var), 0 ); p.first != end(var); ++p.first, ++p.second ) {
/* ... */
}
double iteration with named indexes/iterators:
using std::begin; using std::end;
int i;
std::vector<Foo>::iterator it;
for (std::tie( it, i ) = std::make_pair( begin(var), 0 ); it != end(var); ++it, ++i ) {
/* ... */
}
or bind the above pair on each iteration to better named variables:
using std::begin; using std::end;
for (auto p = std::make_pair( begin(var), 0 ); p.first != end(var); ++p.first, ++p.second ) {
auto const& it = p.first;
int i = p.second;
}

emplace_back when loop of the same list

i present you my problem
I've 2 list, named them A and B.
list<vector<int> > A = {{1},{2},{3}};
list<vector<int> > B = {{4},{5},{6}};
What i want is to have A = {{1,4},{1,5},{1,6},{2,4},{2,5},{2,6},{3,4},{3,5},{3,6}} without use any tmp list.
I use C++11 with gcc 4.6.3 on Ubuntu 12.04
So that the minimize code:
auto A_begin = A.begin();
auto A_end = A.end();
auto B_begin = B.begin();
auto B_end = B.end();
for(auto i = A_begin; i != A_end; ++i) //loop on A
{
for (auto j = B_begin;j != B_end; ++j) //loop on B
{
vector<int> tmp = (*i); // A[i]
copy((*j).begin(),(*j).end(),back_inserter(tmp)); // append B[j] to A[i]
A.emplace_back(tmp); //add it to A
}
}
A.erase(A_begin,A_end); // remove {1},{2},{3}
So, i think the algo is ok, but it make a infinit loop on A.
That I think is that A_end change when i make a A.emplace_back, but i save it, so i realy don't know wat append here.
my code to identify the problem:
auto A_begin = A.begin();
auto A_end = A.end();
auto B_begin = B.begin();
auto B_end = B.end();
int ii = A.size();
for(auto i = A_begin; i != A_end; ++i) //loop on A
{
for (auto j = B_begin;j != B_end; ++j) //loop on B
{
vector<int> tmp = (*i);
A.emplace_back(tmp);
}
cout<<--ii<<endl; // exit when print 0 ?
}
This print negative number, and I've to ^C again.
EDIT : I find a solution:
auto A_begin = A.begin();
auto A_end = A.end();
auto B_begin = B.begin();
auto B_end = B.end();
list<vector<int>> tmp_l;
for(auto i = A_begin; i != A_end; ++i) //loop on A
{
for (auto j = B_begin;j != B_end; ++j) //loop on B
{
vector<int> tmp = (*i); // A[i]
copy((*j).begin(),(*j).end(),back_inserter(tmp)); // append B[j] to A[i]
tmp_l.emplace_back(move(tmp)); //add it to A
}
}
swap(tmp_l,A);
These two lines:
vector<int> tmp = (*i); // A[i]
copy((*j).begin(),(*j).end(),tmp.end()); // append B[j] to A[i]
will be invoking undefined behaviour. By copying to tmp.end() you are simply overwriting memory after the end of A[i], not extending A[i]. You need to use a back_insert iterator, something like:
vector<int> tmp = (*i); // A[i]
copy((*j).begin(), (*j).end(), back_inserter(tmp)); // append B[j] to A[i]
You'll also need to include the header to get the back_inserter.
EDIT: Also, the A_end iterator points to the position "past the end" of the list so no matter how many items you add to a they are always added in front of A_end, hence the infinite loop. I'm not sure if there's a good way to deal with this. There's no benefit here in not creating a temporary list, you are allocating the same memory either way, just write into a new list.
Your algorithm is not good.
This :
copy((*j).begin(),(*j).end(),tmp.end());
will cause all kind of problems because you overwrite some random memory.
You probably wanted to do something like this to append :
vector<int> tmp = (*i);
copy((*j).begin(),(*j).end(),std::back_inserter(tmp));
EDIT : I find a solution:
That solution is good, using a temporary vector and swapping it with A is better than doing it in place, because your original version (as well as copying past the end of the vectors) finished with an erase from the beginning which moves every element.
But your solution can be improved:
// get rid of these iterators, they're useless
/*
auto A_begin = A.begin();
auto A_end = A.end();
auto B_begin = B.begin();
auto B_end = B.end();
*/
list<vector<int>> tmp_l;
// use new for loops
for (auto& a : A)
{
for (auto& b : B)
{
// use auto
auto tmp = a; // A[i]
// I find just inserting at the end simpler than using `back_inserter`
tmp.insert(tmp.end(), b.begin(), b.end()); // append B[j] to A[i]
// then clear it the moved-from elements:
b.clear();
// move the tmp vector into place, do not copy it.
tmp_l.emplace_back(std::move(tmp));
}
}
swap(tmp_l,A);