【问题标题】:How to remove elements from vector given another vector of iterators给定另一个迭代器向量,如何从向量中删除元素
【发布时间】:2015-04-21 06:05:13
【问题描述】:

我有两个向量

vector<int> vint;
vector<vector<int>::iterator> viter;

删除vint 中所有迭代器存在于viter 中的元素的最佳方法是什么。目前,我临时改用list

编辑:(更多背景)

这是我当前的代码。我希望我可以避免移动到列表并返回到矢量

void foo(std::vector<Blah>& bvec)
{
  std::list<Blah> blist;
  std::move(bvec.begin(), bvec.end(), std::back_inserter(blist));
  bvec.clear();
  std::vector<std::list<Blah>::iterator> selectedElements;
  { 
     //Critical section which holds a mutex. Should be as fast as possible
     for(auto it = blist.begin(), it_end= blist.end(); it != it_end; ++it)
     {
        if(shouldElementBeRemoved(*it))
           selectedElements.push_back(it);
     }
  }
  for(auto& it: selectedElements)
  {
     if(shouldElementReallyBeRemoved(*it))
        blist.erase(it);
  }
  std::move(blist.begin(), blist.end(), std::back_inserter(bvec));
}

如果我可以直接从向量中删除,可以在没有列表的情况下进行简化。

void foo(std::vector<Blah>& bvec)
{
  std::vector<std::vector<Blah>::iterator> selectedElements;
  { 
     //Critical section which holds a mutex. Should be as fast as possible
     for(auto it = bvec.begin(), it_end= bvec.end(); it != it_end; ++it)
     {
        if(shouldElementBeRemoved(*it))
           selectedElements.push_back(it);
     }
  }
  for(auto& it: selectedElements)
  {
     if(shouldElementReallyBeRemoved(*it))
        // bvect.erase(it);              //Not safe!
  }
}

【问题讨论】:

  • 我不清楚您所说的“vint 中的所有元素,其迭代器都存在于 viter 中”
  • 这些迭代器实际上是从vint 收集的吗?为什么必须暂时将它们复制到list?我不明白这一点。对vint 调用的简单(反向)循环和std::vector::erase() 不适合您吗?
  • 如果第二个向量中的迭代器指向 vint,则不能使用擦除,因为您将使迭代器无效。但是,如果迭代器指向另一个向量擦除将完成这项工作
  • 您可以使用来自vint 的迭代器在vint 上调用erase(),但您必须小心。 erase() 使其后面的所有迭代器无效,因此您必须从后面向前擦除
  • 如果你有索引而不是迭代器会更好。然后你可以对它们进行排序并先删除较大的。

标签: c++ c++11 stdvector


【解决方案1】:

您应该能够使用您的第二个 sn-p 并稍作修改 - 而不是向前迭代 selectedElements,而是向后迭代。那么对bvec.erase 的调用将永远不会使保留在selectedElements 中的任何迭代器失效。

void foo(std::vector<Blah>& bvec)
{
  std::vector<std::vector<Blah>::iterator> selectedElements;
  selectedElements.reserve(bvec.size());  // avoid growing the vector while you hold a mutex lock

  { 
     //Critical section which holds a mutex. Should be as fast as possible
     for(auto it = bvec.begin(), it_end= bvec.end(); it != it_end; ++it)
     {
        if(shouldElementBeRemoved(*it))
           selectedElements.push_back(it);
     }
  }
  for(auto first = selectedElements.rbegin(),
           last  = selectedElements.rend();
           first != last;
           ++first)
  {
      if(shouldElementReallyBeRemoved(**first)) 
        bvec.erase(*first);
  }
}

Live demo

【讨论】:

    【解决方案2】:

    这似乎对我来说是正确的:

    #include <algorithm>
    
      for (auto current = vint.end();
           current >= vint.begin();) {
        current--;
        if (any_of(
              viter.begin(),
              viter.end(),
              [current](std::vector<int>::iterator it) {
                return current == it;
              })) {
          vint.erase(current);
        }
      }
    

    使用any_of 允许对迭代器向量进行未排序。

    【讨论】:

    • +1 简单明了。适用于小向量。不适合大的,因为将复杂性更改为 O(N^2)
    【解决方案3】:

    也许这适合您的情况:

    struct Blah
    {
        bool deleted = false; // add a special field
        // other data
    };
    
    void foo(std::vector<Blah>& bvec)
    {
        {
            //Critical section which holds a mutex. Should be as fast as possible
            // mark them quickly
            for(auto& b: bvec)
                if(shouldElementBeRemoved(b))
                    b.deleted = true;
        }
    
        // remove them slowly
        for(auto i = bvec.begin(); i != bvec.end();)
        {
            if(i->deleted && shouldElementReallyBeRemoved(*i))
                i = bvec.erase(i);
            else
            {
                i->deleted = false;
                ++i;
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2018-07-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-20
      • 1970-01-01
      • 2014-09-04
      • 2017-01-01
      • 1970-01-01
      相关资源
      最近更新 更多