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.