I am looking for a readable, elegant way to do the following in C++, here shown in Python:
for datum in data[1:]:
# do work.
The iterators on the data in question may not support random access iterators, so I can't just use:
for (mIter = data.begin() + 1; mIter != data.end(); mIter++)
The best I've come up with is the following:
iterable::iterator mIter = data.begin();
for (mIter++; mIter != allMjds.end(); mjdIter++) {
// do work.
}
It's not too lengthy, but it's hardly expository - at first glance it actually looks like a mistake!
Another solution is to have an "nth element" helper function, I guess. Is there a more concise way?
You can use std::next(iter, n) for a linear-time advance. You can also use the standard std::advance algorithm, though it isn't as simple to use (it takes the iterator by a non-const reference and doesn't return it).
For example,
for (mIter = std::next(data.begin()); mIter != data.end(); ++mIter)
or,
mIter = data.begin();
std::advance(mIter, 1);
for (; mIter != data.end(); ++mIter)
Note that you must make sure that data.size() >= 1, otherwise the code will fail in a catastrophic manner.
#include <iterator>
iterator iter = data.begin();
for (advance(iter, 1); iter != data.end(); ++iter)
{
// do work
}
This relies on >= 1 element in data to avoid an exception, though.
You could try:
for (mIter = data.begin() ; ++mIter != data.end() ; )
but you'd need to make sure that if data.begin () == data.end () doing the ++mIter doesn't cause a problem.
Since this is a non-standard for loop, using a while loop might be more appropriate as there are fewer preconceived ideas about how they work, i.e. people looking at your code are more likely to read a while statement than a for statement as there is usually a model of how a for loop should work in their head.
mIter = data.begin ();
while (++mIter != data.end ())
{
}
You can use boost::next for this (but you should be sure that the list actually has an element in it before doing so):
#include <algorithm>
#include <iostream>
#include <iterator>
#include <list>
#include <boost/assign.hpp>
#include <boost/next_prior.hpp>
using namespace boost::assign;
int main()
{
std::list<int> lst = list_of(23)(9)(84)(24)(12)(18);
std::copy(boost::next(lst.begin()), lst.end(), std::ostream_iterator<int>(std::cout, " "));
return 0;
}
iterable::iterator mIter = data.begin();
std::for_each(++mIter, data.end(), some_func);
where some_func contains the code you want to execute... you could even trivialise it with a simple wrapper function
template <typename _cont, typename _func>
for_1_to_end(_cont const& container, some_func func)
{
typename _cont::const_iterator it = _cont.begin();
std::for_each(++it, _cont.end(), func);
}
This is how i would do it
// starting position in the list
int i = 4;
// initialize "it" to point to the first item of data.
std::list<int>::iterator it = data_list.begin();
if (i < data.size()) {
// loop starting from 4 to end of the list.
for (std::advance(it, i); it != token_list.end(); it++) {
//use "it" here
}
}
else {
// Error: starting point is greater than size of data
}
What might be a good solution in a modern c++ way :
std::for_each(cbegin(data)+1,cend(data),[&](const auto& elem)
{
//do whatever you want with elem here
});
This will work even if data is empty. It's basically possible to use this in the exact same way as you would do it with a standard for-range loop and has the advantage not to require any additional variable while keeping the code readable.
Algorithm library : https://en.cppreference.com/w/cpp/algorithm
Related
I'm iterating through a vector as follows:
for(auto it = myVector.begin(); it != myVector.end(); ++it){
// Do some stuff
}
Inside the loop, based on some condition, I add a variable amount to the iterator so as to "jump forward" (but, importantly, never "move back"). What is the "right" way (or, at least, what is an effective/reliable way) to "clamp" the iterator such that I don't end up going beyond the end of the vector (ending up with a program crash or, worse yet, undefined behaviour)?
if (myVector.end() - it < variable_amount)
it += variable_amount;
else
break;
Using std::distance and std::advance would allow this to work with non-random access iterators, but that would be an inefficient algorithm for them, so I recommend not using them.
Algorithm for non-random-access iterators:
for (; variable_amount-- && it != myList.end(); ++it);
You can make your own version of advance that will never go past the end iterator. Adapted from https://en.cppreference.com/w/cpp/iterator/advance
// Assumes c++11 at least
template<class It, class Distance>
constexpr void clamped_advance(It& it, It limit, Distance n) {
using category = typename std::iterator_traits<It>::iterator_category;
static_assert(std::is_base_of<std::input_iterator_tag, category>::value, "Cannot advance non-input iterator");
auto dist = typename std::iterator_traits<It>::difference_type(n);
assert(("Can only clamped_advance forward", dist >= 0));
if (std::is_base_of<std::random_access_iterator_tag, category>::value)
std::advance(it, std::min(dist, std::distance(it, limit)));
else
while (dist-- > 0 && it != limit) ++it;
}
And you can use it like:
for (auto it = myVector.begin(); it != myVector.end(); ++it) {
// Do some stuff
// If this was going to advance past the end, `it` would equal `myVector.end()`
// and the loop will stop
clamped_advance(it, myVector.end(), variableAmount);
}
I would begin by getting the distance between the current iterator and the begin iterator.
If that distance plus the offset is larger than the vector size, you're going out of bounds.
I have a list of integers.(Currently stored in a std::vector but to increase efficieny, I need to convert it to set. But in current version, I use it as following: (I'm using c++98 not c++11)
int res=0;
vector<vector<int> >costMatrix;
vector<int>partialSolution;
for(int i =0;i<partialSolution.size()-1;i++){
res+=costMatrix[partialSolution.get(i)][partialSolution.get(i+1)];
}
So, I need to do the same thing with the set data structure. But I dont know how to get two elements from the set at a time. I can get the partialSolution.get(i) with the code below but I could not get the partialSolution.get(i+1). Is there anyone to help me to modify the code below?
// this time set<int> partialSolution
int res=0;
std::set<int>::iterator it;
for (it = partialSolution.begin(); it != partialSolution.end(); ++it)
{
res+=costMatrix[*it][];
}
This could work (iterating from begin() to end()-1 and using std::next or ++ to get item next to current one).
In C++11:
for (it = partialSolution.begin(); it != std::prev(partialSolution.end()); ++it)
{
res+=costMatrix[*it][*(std::next(it))];
}
In C++98:
std::set<int>::iterator last = partialSolution.end();
--last;
for (it = partialSolution.begin(); it != last; ++it)
{
// not optimal but I'm trying to make it easy to understand...
std::set<int>::iterator next = it;
++next;
res+=costMatrix[*it][*next];
}
I have a structure like this:
struct client
{
string name;
double money;
};
I also have 2 predicates:
bool less_10(const client& a)
{
return a.money < 10;
}
bool not_a(const client& a)
{
return a.name.at(0) != 'A';
}
In my main function I use this to filter out the result stored in vector client_list (everyone with money < 10 (choice 1) or everyone with name not start with A (else))
if (choice_filter == 1)
{
vector<client>::iterator it3;
it3 = find_if(client_list.begin(), client_list.end(), less_10);
while (it3 != client_list.end())
{
**client_list.erase(it3);
it3 = find_if(it3 + 1, client_list.end(), less_10);
}
client_list.erase(it3);**
}
else
{
vector<client>::iterator it4;
it4 = find_if(client_list.begin(), client_list.end(), not_a);
while (it4 != client_list.end())
{
**client_list.erase(it4);
it4 = find_if(it4 + 1, client_list.end(), not_a);
}
client_list.erase(it4);**
}
I notice that if I erase first, then find_if, i'll lost the last client. So i added 1 more line to erase, but the program crashes as iterator is now at the end, cant erase.
Is there any way to get around this? I want to keep using find_if with predicates as well as while loop like above as they are required.
As others have said, std::remove_if is the best solution. If
you're doing this for pedagogical reasons (which I suspect is
the case, given these particular predicates): you're on the
right track. The only issue is that client_list.erase
invalidates the iterator. But since it returns an iterator to
the element immediately after the element it erased, you can use
something like:
std::vector<Client>::iterator it
= std::find_if( client_list.begin(), client_list.end(), predicate );
while ( it != client_list.end() ) {
it = client_list.erase( it );
it = std::find_if( it, client_list.end(), predicate );
}
And you don't want to call erase after the loop. The iterator
designates the end, where there is no element to be erased.
The typical way to go is to use a temporary vector:
vector<client> tmp;
for (...)
{
if(predicate(it))
tmp.push_back(*it);
}
client_list.swap(tmp);
This is similar to what Chris suggested in a comment, although that solution would first move elements to the end of the vector and then truncate them from there. I'm not sure if that doesn't change the order on the way, just check the documentation. Depending on what you want, either could do the work though.
If you used a different container like list<> that did not invalidate all iterators in erase(), you could do this:
it = c.begin();
end = c.end();
while(it != end)
{
if(predicate(*it))
{
c.erase(it++);
}
else
{
++it;
}
}
Note that if you call erase(), you invalidate that iterator still, hence the iterator is first incremented and erase() is called with the former value using the postfix increment.
I also agree with chris, to using std::remove_if:
{
remove_if(client_list.begin(), client_list.end(), less_10);
}
But if you want to reinvent the wheel:
{
vector<client>::iterator it3 = client_list.begin();
while (true)
{
it3 = find_if(it3, client_list.end(), less_10);
if (it3 == client_list.end()) {
break;
}
it3 = client_list.erase(it3);
}
}
My problem is as follows: I use an iterator, and I want to compare each element to the next element. Prototype looks like below, how can I increase the iterator to be able to compare?
Also, how can I set a proper condition for this to happen? I mean how to point on the last element, not on the next after the last like with end() function:
std::vector<T>::const_iterator it;
std::vector<T>::const_iterator it2;
for (it = set.begin(), it != set.end(); it++)
{
// some things happen
if ( final == it )
{
if ( it != set.end()-1 ) // how to write properly condition?
{
it2 = it + 1; //how to assign the next here?
if (...)//some condition
{
if ( it->func1() - it2->func1()) < 20 ) //actual comparison of two consecutive element values
// do something
}
}
}
}
In C++11 use the functions std::next() and std::prev().
Your code could become:
// before
it != std::set.end()-1
// after
it != std::prev(set.end())
and
// before
it2 = it + 1;
// after
it2 = std::next(it);
That is true also for non-vector containers, such as map,set or others.
NOTE: after std::next(it), "it" iterator remains unmodified!
NOTE 2: Use it2 = std::next(it,n); to increment as much as you need.
You can use adjacent_find to solve that. You should use the second form of that function (with predicate) and pass to the predicate your some things happen and some condition in c-tor
auto found = std::adjacent_find( set.begin(), set.end(),
[some_comdition]( const T & left, const T & right ) {
if ( some_comdition ) {
if ( left.func1() - right.func1() < 20 ) {
do_smth();
// return true; if there's no need to continue
}
}
return false;
}
);
Based on the fact that it++ is acceptable, we should define a new iterator called itplusone, which is initialized as itplusone = ++it. In this way, you can safely use the meaning of an iterator pointing to the next item of it. Also clearly, the range of iterator of itplusone bounded by terms itplusone != set.end(). I use this method to compute the total weight of a path, which is defined as a list object.
In the for loop, you use it++ which means it = it + 1, which is perfectly ok. So this one will be fine also it2 = it + 1. it2 will be pointing to the next value.
In the for loop again, you use it != set.end(), which is again perfectly ok. So you can also it + 1 < set.end(), just like you did in your code.
I don't see anything wrong in your code, just wanted to explain.
somewhat late, just discovered it, but like mentioned above, ++ iterator works fine.
vector<string> P
auto itA = begin(P);
while(itA != end(P))
{
if(itA != end(P))
{
++itA; //
}
}
I have a situation where I'm marching through a vector, doing things:
std::vector<T>::iterator iter = my_list.begin();
for ( ; iter != my_list.end(); ++iter )
{
if ( iter->doStuff() ) // returns true if successful, false o/w
{
// Keep going...
}
else
{
for ( ; iter != m_list.begin(); --iter ) // ...This won't work...
{
iter->undoStuff();
}
}
}
Under normal conditions - assuming everything goes well - I march all the way to my_list.end() and end the loop successfully.
However, if something goes wrong while I'm doing stuff, I want to be able to undo everything - basically retrace my steps back to the very beginning of the vector, undoing everything one at a time in reverse order.
My problem is that when I get to my_list.begin() - as shown in the nested for loop - I'm really not done yet because I still need to call undoStuff() on my first element in the list. Now, I could just make the final call outside of the loop, but this seems a little unclean.
The way I see it, I'm only done when I get to my_list.rend(). However, I can't compare a std::vector::iterator to a std::vector::reverse_iterator.
Given what I'm trying to do, what's the best choice of iterator-type / loop combination?
I'm a little rusty when it comes to STL vectors, but would it be possible to create a std::vector::reverse_iterator from your initial iterator? Then you would only need to start at the last item you were at when going forward, and would be able to compare it to my_list.rend() to make sure that the first item is processed.
While using reverse iterators via rbegin() and rend() works nicely, unfortunately I find that converting between reverse and non-reverse iterarotrs tends to be quite confusing. I can never remember without having to go through a logic-puzzle exercise whether I need to increment or decrement before or after the conversion. As a result I generally avoid the conversion.
Here's the way I'd probably code your error handling loop. Note that I'd think that you wouldn't have to call undoStuff() for the iterator that failed - after all, doStuff() said it didn't succeed.
// handle the situation where `doStuff() failed...
// presumably you don't need to `undoStuff()` for the iterator that failed
// if you do, I'd just add it right here before the loop:
//
// iter->undoStuff();
while (iter != m_list.begin()) {
--iter;
iter->undoStuff();
}
There is of course no reason not to use the vectors operator[]() if that makes your code clearer, simpler and/or more efficient.
It depends on what your doStuff() function does, and how important performance is in your context. If possible, it would probably be clearer (ie - easier for the reader) to work on a copy of your vector, and only if everything is okay, swap the vectors.
std::vector<Foo> workingCopy;
workingCopy.assign(myVector.begin(), myVector.end());
bool success = true;
auto iter = workingCopy.begin();
for( ; iter != workingCopy.end() && success == true; ++iter )
success = iter->doStuff();
if( success )
myVector.swap(workingCopy);
Without using a reverse_iterator, you can walk backwards this way:
while(iter-- != m_list.begin())
{
iter->undoStuff();
}
Though this creates a copy of iter, the cost shouldn't be too great. You can refactor for better speed:
while(iter != m_list.begin())
{
--iter;
iter->undoStuff();
}
You need to use rbegin() to get a reversible iterator.
Personally I still prefer
for (int i=0;i<vecter.size();i++) { }
Ok, I'll go out on a limb here..
std::vector iterator iter = my_list.begin();
bool error = false;
while(iter != my_list.end())
{
error = !iter->doStuff();
if(error)
break
else
iter++;
}
if(error)
do
{
iter->undoStuff();
iter--;
}
while(iter != my_list.begin())
This is what I call over engineering, but it is so much fun
// This also can be done with adaptators I think
// Run DoStuff until it failed or the container is empty
template <typename Iterator>
Iterator DoMuchStuff(Iterator begin, Iterator end) {
Iterator it = begin;
for(; it != end; ++it) {
if(!*it->DoStuff()) {
return it;
}
}
return it;
}
// This can be replaced by adaptators
template <typename Iterator>
void UndoMuchStuff(Iterator begin, Iterator end) {
for(Iterator it = begin; it != end; ++it) {
it->UndoStuff();
}
}
// Now it is so much easier to read what we really want to do
typedef std::vector<MyObject*> MyList;
typedef MyList::iterator Iterator;
typedef MyList::reverse_iterator ReverseIterator;
Iterator it = DoMuchStuff(my_list.begin(), my_list.end());
if(it != my_list.end()) {
// we need to unprocess [begin,it], ie including it
UndoMuchStuff(ReverseIterator(1+it), ReverseIterator(my_list.begin()));
}
This can be done with a reverse_iterator:
bool shouldUndo(false);
std::vector::iterator iter(my_list.begin()), end(my_list.end());
for ( ; iter != end && !shouldUndo; ++iter )
{
shouldUndo = iter->doStuff(); // returns true if successful, false o/w
}
if (shouldUndo) {
reverse_iterator<std::vector::iterator> riter(iter), rend(my_list.rend());
//Does not call `undoStuff` on the object that failed to `doStuff`
for ( ; riter != rend; ++riter )
{
iter->undoStuff();
}
}