std:vector的替代项,用于在遍历循环时删除其元素

Alternative for std:vector to remove its elements while going through a loop?

本文关键字:循环 遍历 删除 元素 用于 vector std      更新时间:2023-10-16

我的循环遍历向量的元素。在这个循环中,一些元素正在被删除(我希望它们被删除)。虽然std::vector不允许这样做,但我想要一个替代方案。

for(unsigned int j = 0; j < rectArray.size(); j++)
{
 if( rectArray[j] == 2 ) 
  {
   rectArray.erase(rectArray.begin() + j);
  }
//...
}

你认为std::列表在这里会好吗?我能用点别的吗?

除非向量的元素复制成本很高,否则最简单的方法可能是将std::copy_if(或以其他方式复制您想要保留的元素)复制到一个新向量中,然后与原始向量交换。还有remove_ifresize

如果元素的重新定位非常昂贵,那么list可以避免这种情况,但这取决于您对集合的其他操作。如果你用list做了其他非常慢的事情,那么你就把问题转移到了其他地方。

我建议修改您的代码,使其使用迭代器而不是实际的向量。它像这样更清洁、更高效:

for (auto it = rectArray.begin(); it != rectArray.end(); ++it)
{
    // Access the current element with *it
    // If you want you can pass `it` and `rectArray.end()` as
    // the lower and upper bounds of the new collection,
    // rather than doing expensive resizes of the vector.
}

注意,auto是一个C++11特性(我使用它的方式)。如果您的编译器支持,您可能还想使用C++11的foreach:

for (auto it : rectArray) {
   // same as before
} 

从向量中间删除一个元素是非常昂贵的,因为您必须向下移动所有后面的元素。

如果您需要在容器的中间添加/删除元素,那么列表通常会更好。

列表比向量更好,因为从列表中间删除元素不会花费任何费用。另一方面,从向量中间移除元素具有线性复杂性。

std::remove_if的可能替代品。速度快一点,不需要函子,但它不维持秩序。

auto end = std::end(rectArray);
for(auto it = std::begin(rectArray); it != end; ++it)
{
    if(it->remove_me()))    
        std::swap(*it, *--end); // or even faster *it = std::move(*--end);
}    
rectArray.erase(end, std::end(rectArray));

如果您正在进行大量删除,那么列表可能是最佳选择。下面是一些示例代码。

#include <vector>
#include <list>
#include <algorithm>
using namespace std;
class Widget
{
public:
   explicit Widget(int someNumber);
   bool ShouldDelete();
   bool ShouldDeleteComplex(int a, int b, int c);
private:
   int _someNumber;
};
Widget::Widget(int someNumber) : _someNumber(someNumber)
{
}
bool Widget::ShouldDelete()
{
   if (_someNumber > 2)
   {
      return true;
   }
   return false;
}
bool Widget::ShouldDeleteComplex(int a, int b, int c)
{
   if ((a * b - c) > _someNumber)
   {
      return true;
   }
   return false;
}
int main()
{
   list<Widget> lw;
   lw.push_back(Widget(1));
   lw.push_back(Widget(2));
   lw.push_back(Widget(3));
   // delete from list using functor
   lw.remove_if(mem_fun_ref(&Widget::ShouldDelete));
   // delete from list using lambda function
   lw.remove_if([] (Widget& x) { return x.ShouldDeleteComplex(1, 2, 0); }   );
   vector<Widget> vw;
   vw.push_back(Widget(1));
   vw.push_back(Widget(2));
   vw.push_back(Widget(3));
   // delete using functor
   vw.erase(remove_if(vw.begin(), vw.end(), mem_fun_ref(&Widget::ShouldDelete)), vw.end());
   // delete using lambda function
   vw.erase(
      remove_if(vw.begin(), vw.end(), 
        [] (Widget& x) { return x.ShouldDeleteComplex(1, 2, 0); }
     ), 
      vw.end());
   return 0;
}