7

I wanted to remove the elements of the vector based on the index, say all the even indexed elements. I have read about the erase remove idiom but can't see how to apply it. This is what I tried:

    vector<int> line;
    line.reserve(10);
    for(int i=0;i<10;++i)
    {
      line.push_back(i+1);
    }
    for(unsigned int i=0;i<line.size();++i)
    {
      //remove the even indexed elements
      if(i%2 == 0)
      {
        remove(line.begin(),line.end(),line[i]);
      }
    }
line.erase( line.begin(),line.end() );

This erases the entire vector. I was hoping to only remove the elements that had been marked by the remove algorithm.

Then I tried this

for(unsigned int i=0;i<line.size();++i)
    {
      //remove the even indexed elements
      if(i%2 == 0)
      {
        line.erase( remove(line.begin(),line.end(),line[i]),line.end() );
      }
    }

This again doesn't work as there is a problem while removing, the indices seem to shift whilst iterating over the vector. What should be the correct approach to accomplish this.

nikhil
  • 8,925
  • 21
  • 62
  • 102

5 Answers5

10

By going from 0 to size, you'll end up skipping half of the elements because the indices change as you erase the elements. Make your for loop go from size() to 0:

for(unsigned int i = line.size(); i > 0; i--)
{

}
Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
JosephH
  • 8,465
  • 4
  • 34
  • 62
  • 2
    I hope you mean `size() - 1`? – Some programmer dude Dec 08 '11 at 07:46
  • 3
    no. that would mess up the loop if the size == 0. Whenever you're referring to the element, just go [i-1] – JosephH Dec 08 '11 at 07:49
  • 1
    `for(std::vector::iterator it = line.end(); it != line.begin(); --it)`? – Mateen Ulhaq Dec 08 '11 at 08:01
  • @AusCBloke no. it's `unsigned int` meaning that `i` would actually be greater than 0 even when it's `-1==0xFFFFFFFF=4294967295` and you'd go into a near infinite loop. – JosephH Dec 08 '11 at 08:14
  • @JosephH: haha woops, my bad, didn't register the `unsigned` part, just saw the `int`. +1 for that. – AusCBloke Dec 08 '11 at 08:15
  • That wouldn't actually work for me. It'll add a few extra checks. I'm looking for an elegant way to do this. – nikhil Dec 08 '11 at 08:28
  • @nikhil this _is_ the elegant way if you're sticking with `for` loops. You can always use `remove_if` as freerider mentioned – JosephH Dec 08 '11 at 08:30
  • `for (unsigned int i=line.size(); i-- != 0;)` requires no `[i-1]` chicanary in every location where `i` would normally be used in the loop body. – WhozCraig Apr 17 '14 at 01:00
5

Online Demo:

#include <vector> 
#include <algorithm>
#include <iostream>

/*Check if Index is Even or Odd*/ 
bool is_IndexEven(int i) 
{
   static int k = 1;

   /*Handle Index 0 as special case as per choice*/
   if(k == 1)
   {
       k++;
       return false;
   } 

   if(k++ % 2)
       return true;
   else 
       return false; 
 }

int main() 
{
    using namespace std;
    int elements[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };

    // create a vector that holds the numbers from 0-9.
    vector<int> v(elements, elements + 10); 

    /*Display elements before removal*/    
    vector<int>::const_iterator iter = v.begin();
    cout<<"Before\n";

    for(iter;iter!= v.end();++iter)
    {
        cout<<*iter;
    }

    /*Remove_if + Erase Algorithm for one step removal*/
    v.erase( remove_if(v.begin(), v.end(), is_IndexEven), v.end() ); 

    /*Display result after elements removed*/
    cout<<"\nAfter\n";
    iter = v.begin();
    for(iter;iter!= v.end();++iter)
    {
       cout<<*iter;
    }

    return 0;
}
Alok Save
  • 202,538
  • 53
  • 430
  • 533
  • 1
    +1. However, it looks like `remove_if` removes elements based on their values. Is this correct? What if we want to remove vector elements based on their index? – Alexey Jul 23 '12 at 20:42
  • 4
    As Benjamin Lindley comments on [an analogous answer to this similar question](http://stackoverflow.com/questions/23122555/removing-by-index-from-a-c-vector-using-remove-if), "This makes an assumption about the order in which `remove_if` applies the predicate, which is not warranted by the standard text.". – Tony Delroy Apr 17 '14 at 02:08
4

Why don't you use remove_if? Use a static variable inside the function to signal the index for the current element.

Lucian
  • 3,407
  • 2
  • 21
  • 18
  • 2
    In addition to the answer above, the example code in this link does exactly what you (OP) are looking for: http://www.cplusplus.com/reference/algorithm/remove_if/ – yasouser Dec 08 '11 at 09:30
  • 2
    @yasouser, no it does not, the example code removes items based on the values being even or not, not their index. – Ton van den Heuvel Jul 16 '18 at 21:09
1

An answer that generalizes not only upon the type of container to be handled but also upon the type of container that holds the indices to be removed, is given in : Erasing elements in stl::vector by using indexes

Community
  • 1
  • 1
Nikos Athanasiou
  • 29,616
  • 15
  • 87
  • 153
1

Here is how to use erase-remove method to remove odd numbers from a vector. I am not sure whether you can remove elements based on the index, because remove_if() applies the predicate on the values pointed by the iterators rather than the iterator itself.

See the following : http://cplusplus.com/reference/algorithm/remove_if/

#include <iostream>
#include <algorithm>
#include <vector>
#include <iterator>
using namespace std;

int main()
{
    vector<int> v;
    v.push_back(11);
    v.push_back(22);
    v.push_back(33);
    v.push_back(44);
    v.push_back(55);
    v.push_back(66);
    v.push_back(77);
    ostream_iterator<int> printit(cout, " ");

    cout << "Before removing odd numbers" << endl;
    copy(v.begin(), v.end(), printit);


    v.erase(remove_if(v.begin(), v.end(),
          [] (int e) { return e%2 == 1; }), v.end());

    cout << endl;
    cout << "After removing odd numbers" << endl;
    copy(v.begin(), v.end(), printit);
    cout << endl;
}
Sanish
  • 1,699
  • 1
  • 12
  • 21
  • 3
    "I am not sure whether you can remove elements based on the index..." that's the whole point of the question. – Tony Delroy Apr 17 '14 at 02:10