如何擦除双循环中的向量元素
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 删除最后一个元素,但是似乎也没有工作。有什么想法吗?
编辑:修复了区域和中心不同步的问题,但现在只要我调用函数擦除一些轮廓,问题就会立即出现。
【问题讨论】:
您的areas
和contours
在第一次删除后“不同步”。您应该从两者中删除东西,或者想出一些其他方式将区域和轮廓表示为单个项目。
上帝...我什至没有意识到我没有这样做,我什至在我计划的时候考虑过...谢谢。
【参考方案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)组成,在算法中相当于将元素与自身进行比较。以上是关于如何擦除双循环中的向量元素的主要内容,如果未能解决你的问题,请参考以下文章