用于在嵌套容器中删除的擦除删除惯用语? (删除外部的;C++ STL)

发布于 2024-10-06 08:40:06 字数 2067 浏览 0 评论 0 原文

当我从非嵌套容器(如向量)中删除时,我正在执行以下操作:

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() );
}

这就是所谓的 “删除-删除”习惯用法

现在,我有第二个数据结构vector >deque >,我想根据位集删除外部容器元素(它本身就是内部类型的容器)。

  • 是否可以在此嵌套容器类型上使用擦除-删除习惯用法?
  • 如果可以,怎么可能?
  • 有限制吗? (例如:vec of vec 是可能的,但 deque of vec 则不行)?

我的第一个简单方法如下。我假设remove_if正在按顺序迭代元素并一个接一个地做出决定。 这是一个错误的假设吗?

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() );
}

结果是错误的,因此我在这里寻找正确的解决方案。我想我假设了一些事情,但这些事情并不能得到保证。对我来说,基本问题如下:如何获取内容器的身份以检查是否要删除。
我上面发布的天真的方法只是计数并假设顺序处理。

感谢您的帮助。

Sascha

更新和警告

对于向量或向量,Stas 解决方案运行良好。但我认为这个解决方案不适用于向量双端队列,因为双端队列不是以连续的方式保存的。这意味着函子中索引的计算失败。

有人可以验证吗?

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

孤君无依 2024-10-13 08:40:06

向量中的哪些元素并不重要。如果您定义应删除其中哪些,则它们将被删除。

正如你所说,问题是如何识别向量中的元素。最明显的答案是它的索引 [0;矢量大小 - 1]

借助向量,您可以轻松地通过元素本身获取元素索引。

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

因此,您可以通过 remove_if 算法谓词内的索引轻松识别向量元素。看一下下面的例子。这是非常愚蠢的,并使用硬编码 std::bitset<6>,但这只是一个说明:

#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;
};

使用

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;
}

结果

 two three five 

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 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文