0

I have this situation:

for(auto it = vec.rbegin(); it != vec.rend(); ++it)
{
    if(condition(it))
    {
        //Move it at end;
        break;
    }
}

What is the most efficient/elegant way to move *it at the end of vec?

EDIT: *it, not it

EDIT1: Now I use:

auto val = *it; 
vec.erase((++it).base());
vec.push_back(val);

But I don't think is very efficient...

Mircea Ispas
  • 20,260
  • 32
  • 123
  • 211

2 Answers2

3

To move it to the end:

for(auto it = vec.rbegin(); it != vec.rend(); ++it)
{
    if(condition(it))
    {
        auto val = *it;
        vec.erase((++it).base());
        vec.push_back(val);
        break;
    }
}

To swap with the last element:

for(auto it = vec.rbegin(); it != vec.rend(); ++it)
{
    if(condition(it))
    {
        auto it2 = --vec.end();
        auto val = *it;
        *it = *it2;
        *it2 = val;
        break;
    }
}
Bernhard Barker
  • 54,589
  • 14
  • 104
  • 138
  • And if `it` becomes invalidated by the call to `push_back`? – Benjamin Lindley Feb 23 '13 at 19:50
  • Not really, because the same conditions that would cause `it` to become invalidated would cause `val` to become invalidated. – Benjamin Lindley Feb 23 '13 at 19:52
  • Yes, it will compile. It will give you a reference to the thing that `it` points to. – Benjamin Lindley Feb 23 '13 at 19:53
  • @Dukeling it is reverse iterator and erase works on iterators. The code is something like: auto val = *it; vec.erase((++it).base()); vec.push_back(val); but I don't think is very efficient – Mircea Ispas Feb 23 '13 at 19:54
  • @Felics Why `vec.erase((++it).base());` not `vec.erase(it.base());`? I doubt it can be more efficient. To remove it from it's current position will take as long as `erase` takes and `push_back` takes constant time. – Bernhard Barker Feb 23 '13 at 20:01
  • @Dukeling Here is the answer: http://stackoverflow.com/questions/1830158/how-to-call-erase-with-a-reverse-iterator Please correct the erase(it) to be able to accept your answer – Mircea Ispas Feb 23 '13 at 20:12
  • @Felics Thanks, a split-second look at the picture in the link and it all made sense. Corrected. – Bernhard Barker Feb 23 '13 at 20:22
  • @BenjaminLindley I see you deleted your answer. I think it was still useful for reference sake. – Bernhard Barker Feb 23 '13 at 20:25
1

If prefer standard algorithms over manual loops. So I'd use std::find_if.

If you need to preserve the order of the elements, moving to the end can be done using std::rotate:

auto rit = std::find_if(vec.rbegin(), vec.rend(), [](int i){ return i == 6; });
if (rit != vec.rend()) {
    auto it = rit.base();
    std::rotate(it-1, it, vec.end());
}

If you don't need to keep the order, you can use std::iter_swap:

auto it = std::find_if(vec.rbegin(), vec.rend(), [](int i){ return i == 6; });
if (it != vec.rend())
    std::iter_swap(it, vec.rbegin());

Demo

jrok
  • 54,456
  • 9
  • 109
  • 141