Question

when i'm deleting from a non-nested container like a vector, i'm doing something like:

struct is_to_remove
{
    is_to_remove(dynamic_bitset<>& x) : x(x) {}
    const bool operator()(unsigned int id)
    {
        return x[id];
    }

private:
    dynamic_bitset<> x;
};

inline static void remove_elements_in_vector(vector<unsigned int>& vec, boost::dynamic_bitset<>& to_remove)
{
    // use the erase-remove idiom to remove all elements marked in bitset
    vec.erase( remove_if(vec.begin(), vec.end(), is_to_remove(to_remove)), vec.end() );
}

That is the so called erase-remove idiom.

Now, i have a second data strucurevector<vector<unsigned int> > or deque<vector<unsigned int> >, where i want to delete the outer container elements (which is itself a container of the inner type) according to a bitset.

  • Is it possible to use the erase-remove idiom on this nested container types?
  • If it is, how is it possible?
  • Are there restrictions? (like: vec of vec is possible, but not deque of vec)?

My first and naive approach was the following. I assumed that remove_if is iterating sequentially and in order over the elements and deciding one after the other. Is that a wrong assumption?

struct is_to_remove_new
{
    is_to_remove_new(dynamic_bitset<>& x, unsigned int index) : x(x), index(index) {}
    const bool operator()(vector<unsigned int> & vec)
    {
        return x[index++];
    }

private:
    dynamic_bitset<> x;
    unsigned int index;
};

inline static void remove_elements_in_vectorvector(vector<vector<unsigned int> >& vec, boost::dynamic_bitset<>& to_remove)
{
    // use the erase-remove idiom to remove all elements marked in bitset
    vec.erase( remove_if(vec.begin(), vec.end(), is_to_remove_new(to_remove, 0)), vec.end() );
}

The result is wrong, therefore i'm looking for a correct solution here. I suppose i assumed some things, which aren't guaranteed. For me, the base question is the following: How to get the identity of the inner container for checking if it is to remove..
My naive approach posted above just counts and assumes a sequential processing.

Thanks for your help.

Sascha

Update and Warning

For a vector o vectors, Stas solution is working great. But i think this solution will not work for a deque of vectors because a deque isn't saved in a contiguous way. This means, that the calculation of the index in the functor fails.

Can anyone verify that?

Was it helpful?

Solution

It doesn't matter which elements are in the vector. If you define which of them should be removed, they will be removed.

As you said, the question is how to identify an element in a vector. The most obvious answer is by its index [0; vector_size - 1].

Thanks to a vector, you can easily get an element index, by the element itself.

std::vector<std::string> vec;
vec.push_back("zero");
vec.push_back("one");
vec.push_back("two");

std::string& elem = vec[2];
int index = std::distance(&vec[0], &elem); // get element index by element itself
// index == 2

So, you can easily identify vector elements by indices inside remove_if algorithm predicate. Take a look at the following example. It is pretty silly and use hard-coded std::bitset<6>, but this is just an illustration:

#include <vector>
#include <string>
#include <bitset>

struct ToRemove
{
   ToRemove(std::vector<std::string>& vec, const std::string& mask) 
   : m_vec(vec)
   , m_mask(mask) 
   {}

   bool operator()(std::string& obj)
   {
      const int index = std::distance(&m_vec[0], &obj);
      return m_mask[index];
   }

   std::vector<std::string>& m_vec;
   std::bitset<6> m_mask;
};

Usage

int main (int argc, char const *argv[])
{
   std::vector<std::string> vec;
   vec.push_back("zero");
   vec.push_back("one");
   vec.push_back("two");
   vec.push_back("three");
   vec.push_back("four");
   vec.push_back("five");

   std::string mask = ("010011"); // Remove "zero", "one" and "four"
   vec.erase(remove_if(vec.begin(), vec.end(), ToRemove(vec, mask)), vec.end());

   for (unsigned i = 0; i < vec.size(); ++i)
   {
      std::cout << vec[i] << " ";
   }
   std::cout << std::endl;

   return 0;
}

Result

 two three five 
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top