如何擦除双循环中的向量元素

Posted

技术标签:

【中文标题】如何擦除双循环中的向量元素【英文标题】:How to erase a vector element within double for loop 【发布时间】:2015-04-01 01:51:15 【问题描述】:

我有一个结构的向量

vector<contour> hotspots;

轮廓是我定义如下的结构

struct contour

    double arc;
    double area;
    Point2f center;
    double me;
    double hullArea;
    vector<Point> contourVector;
    vector<Point> hullVector;

    bool operator <(const contour& comp)
    
        return me < comp.me;
    
;

所以我要做的是循环遍历它并删除包含在另一个轮廓中的每个轮廓,我可以让它在大多数情况下工作,但有时我会遇到索引错误,我假设它有事可做当我擦除一个元素时,索引会变得混乱,所以我超出了范围。这是我写的循环:

vector<vector<Point>> cleanUp(vector<Point2f> centers, vector<Moments> areas, vector<vector<Point>> contours)

    for (int i = 0; i < contours.size(); i++)
        for (int j = 0; j < contours.size(); j++)
            if (i != j)
            
                if ((areas[i].m00 < areas[j].m00) == true && (pointPolygonTest(contours[j], centers[i], false) > 0) == true)
                
                    contours.erase(contours.begin() + i);
                    centers.erase(centers.begin() + i);
                    areas.erase(areas.begin() + i);
                
            

    return contours;

我尝试了几种不同的解决方案,例如 i - 1,但删除了错误的轮廓,而不是使用擦除,而是用最后一个覆盖我要删除的元素,然后使用 .pop_back 删除最后一个元素,但是似乎也没有工作。有什么想法吗?

编辑:修复了区域和中心不同步的问题,但现在只要我调用函数擦除一些轮廓,问题就会立即出现。

【问题讨论】:

您的areascontours 在第一次删除后“不同步”。您应该从两者中删除东西,或者想出一些其他方式将区域和轮廓表示为单个项目。 上帝...我什至没有意识到我没有这样做,我什至在我计划的时候考虑过...谢谢。 【参考方案1】:

您可以保留要删除的项目的索引列表,并在最后删除这些索引处的项目。

vector<vector<Point>> cleanUp(vector<Point2f> centers,
                              vector<Moments> areas,
                              vector<vector<Point>> contours)

   std::<int> itemsToErase;

    for (int i = 0; i < contours.size(); i++)
        for (int j = 0; j < contours.size(); j++)
            if (i != j)
            
                if ((areas[i].m00 < areas[j].m00) == true &&
                    (pointPolygonTest(contours[j], centers[i], false) > 0) == true)
                
                   itemsToErase.push_front(i);
                
            

    while  ( !itemsToErase.empty() )
    
       int i = itemsToErase.back();
       contours.erase(contours.begin() + i);
       centers.erase(centers.begin() + i);
       areas.erase(areas.begin() + i);
       itemsToErase.pop_back();
    

    return contours;

【讨论】:

【参考方案2】:

使用迭代器,我会尝试这种方法:

#include <iterator>

template <typename BinaryPred>
void RemoveIfPairwise(std::vector<T> & v, BinaryPred f)

    for (auto it1 = v.begin(); it1 != v.end(); ++it1)
    
        for (auto it2 = std::next(it1); it2 != v.end(); )
        
            if (f(*it1, *it2))  it2 = v.erase(it2); 
            else                ++it2;              
        
    

这使用了std::vector 的迭代器非失效保证,例如擦除不会在擦除点之前使迭代器失效(因此it1 不需要特殊处理)。

请注意,此循环仅检查不同元素对;您需要对其进行修改以检查对角线。

【讨论】:

你能解释一下你所说的对角线是什么意思吗?谢谢。 我认为他的意思是i == j的情况。 v.erase(it2++); 应该是 it2=v.erase(it2);,我能想到的两个原因,都是 UB。 (后增量使用了一个无效的迭代器;如果我们在擦除之后前进,我们可以跳过结束)。 @Yakk:谢谢,非常真实。实际上我最近在一些真实代码中犯了这个错误:-S @JayBell:把你的迭代想象成一个指数的平方(i,j)。当前循环遍历严格的上三角形,对角线由所有对(i,i)组成,在算法中相当于将元素与自身进行比较。

以上是关于如何擦除双循环中的向量元素的主要内容,如果未能解决你的问题,请参考以下文章

使用交换和弹出进行迭代时擦除向量中的元素

从向量中最快擦除元素或更好地使用内存(排序基数)

对于向量中的指针,我们应该在擦除之前还是之后删除?

C ++根据成员函数从向量中擦除对象[重复]

按键擦除矢量元素

C ++没有匹配函数来调用向量中的擦除