9

I have a vector a storing values [0 1 2 3 5] and other vector removelist storing the indexes to be removed [0 1 2] in order to leave [3 5] at the end. When I'm implementing the following code, it would remove items unexpectedly since the vector a will be changing order during the process. Is there any way for me to achieve my target?

 for (int i = 0; i<removelist.size() ; i++) a.erase(a.begin() + removelist[i]); 
5
  • 1
    Is the removelist ordered? Commented Jan 28, 2016 at 7:30
  • @tkausl Even more, everything seems to be ordered. I'd ask if this is the case. Is each array actually ordered? Commented Jan 28, 2016 at 7:33
  • The removelist is not ordered , but it can be sorted if needed. Commented Jan 28, 2016 at 7:35
  • @skypjack it doesn't matter if the a vector is ordered as he removes it by indices not by values. But his example is buggy (there is no index 5 in a vector with size 5) Commented Jan 28, 2016 at 7:36
  • Maybe you misunderstand my question. The removelist is a reference list for removing a[0], a[1] and a[2]. Commented Jan 28, 2016 at 7:42

4 Answers 4

7

Reverse the order you remove values, i.e. use the reverse iterators of removelist. This of course relies on removelist being sorted.

Perhaps something like

std::sort(removelist.begin(), removelist.end()); // Make sure the container is sorted for (auto &i = removelist.rbegin(); i != removelist.rend(); ++ i) { a.erase(a.begin() + *i); } 
Sign up to request clarification or add additional context in comments.

Comments

2

Not necessarily more efficient, but you can do this without sorting using remove_if:

auto& rm = removelist; // for brevity a.erase(remove_if(begin(a), end(a), [&](int i) { auto idx = distance(begin(v), find(begin(v), end(v), i)); return find(begin(rm), end(rm), idx) != end(rm); }, end(a)); 

1 Comment

NOTE: Using find(begin(v), end(v), i) will lead to unexpected result when there are the elements in the vector v are not unique.
1

The solution to this is to copy the elements you want to keep to a new vector:

// pseudocode: vector tmp; tmp.reserve(a.size() - removelist.size()); for (i=0; i<a.size(); ++i) { if (i not in removelist) { tmp.push_back(a[i]); } } a.swap(tmp); 

Notes:

  • You have to make sure that the indices are unique, otherwise the preallocation fails.
  • This avoids various reallocations using the preallocated, temporary vector. The reallocations of a also avoid the index shift in your approach.
  • If the elements in removelst are sorted, this can be implemented a bit more efficiently.
  • I wonder where that list comes from. Can't you remove the elements on the fly instead of creating a temporary list?

1 Comment

The temporary list is generated by some comparisons.
0

Adapted from @Yam Marcovic's answer, not using find but use the exact address to find the index:

a.erase(std::remove_if(a.begin(), a.end(), [&](const int& i) { auto idx = ((void*)&i - (void*)&*a.begin()); return std::find(removelist.begin(), removelist.end(), idx) != removelist.end(); }), a.end()); 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.