Remove vector elements based on the index
Asked Answered
T

5

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.

Tropopause answered 8/12, 2011 at 7:37 Comment(0)
M
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;
}
Markswoman answered 8/12, 2011 at 8:4 Comment(2)
+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?Handgun
As Benjamin Lindley comments on an analogous answer to this similar question, "This makes an assumption about the order in which remove_if applies the predicate, which is not warranted by the standard text.".Cohin
E
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--)
{

}
Empathy answered 8/12, 2011 at 7:39 Comment(8)
I hope you mean size() - 1?Hardwick
no. that would mess up the loop if the size == 0. Whenever you're referring to the element, just go [i-1]Empathy
for(std::vector<int>::iterator it = line.end(); it != line.begin(); --it)?Mannerly
@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.Empathy
@JosephH: haha woops, my bad, didn't register the unsigned part, just saw the int. +1 for that.Octavie
That wouldn't actually work for me. It'll add a few extra checks. I'm looking for an elegant way to do this.Tropopause
@Tropopause this is the elegant way if you're sticking with for loops. You can always use remove_if as freerider mentionedEmpathy
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.Briefing
M
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;
}
Markswoman answered 8/12, 2011 at 8:4 Comment(2)
+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?Handgun
As Benjamin Lindley comments on an analogous answer to this similar question, "This makes an assumption about the order in which remove_if applies the predicate, which is not warranted by the standard text.".Cohin
S
4

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

Selfconscious answered 8/12, 2011 at 7:44 Comment(2)
In addition to the answer above, the example code in this link does exactly what you (OP) are looking for: cplusplus.com/reference/algorithm/remove_ifSeam
@yasouser, no it does not, the example code removes items based on the values being even or not, not their index.Hawking
B
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;
}
Beyond answered 8/12, 2011 at 8:28 Comment(1)
"I am not sure whether you can remove elements based on the index..." that's the whole point of the question.Cohin
P
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

Proficiency answered 15/1, 2014 at 21:45 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.