C++ nested for loop with erasing elements

你离开我真会死。 提交于 2021-02-11 14:10:27

问题


I would like to check all Elements of an vector against each other. By checking a condition an element should be removed.

One approach was to erase the elements by nested for loops

for (int a = 0; a < rs.size(); a++)
{
    Point A = rs[a];

    for (int b = 1; b <= rs.size(); b++)
    {
        Point B = rs2[b];
        float distance = sqrt(pow(B.x - A.x, 2) + pow(B.y - A.y, 2) * 1.0);

        if (distance < 10.0)
        {
            if (distance > 0)
            {
                rs.erase(rs.begin() + b);
            }
        }
    }
}

but this would effect the vector and his size in runtime.

A second approach was to collect the index of b in an unordered_set but how can I delete the elements with the correspondig index in the original vector?

unordered_set<int> index;

for (int a = 0; a < rs.size(); a++)
{
    Point A = rs[a];

    for (int b = 0; b < rs.size(); b++)
    {
        Point B = rs2[b];
        float distance = sqrt(pow(B.x - A.x, 2) + pow(B.y - A.y, 2) * 1.0);

        if (distance < 10.0)
        {
            if (distance > 0)
            {
                index.insert(b);
            }
        }
    }
}

As you might expect, this approach does not work either:

for (const int& idx : index)
{
    rs.erase(rs.begin() + idx);
}

Any help?


回答1:


You can delete indices from a vector with a reverse loop in the last suggestion you made. Just make that index a vector. Let's call it toRemove.

for (int i = toRemove.size() - 1; i >= 0; i--)
{
    rs.erase(rs.begin() + toRemove[i]);
}

Just be careful that this loop has to have a signed index. Otherwise you may underflow. You can make this "nicer" with a reverse iterator. This is just a proof of concept.




回答2:


To be as robust as possible, I would go with std::for_each. In the function performed on each object, roughly:

  • perform the calculation necessary
  • check for your condition of whether to keep the element or not
  • if you want to keep it, add it to a new out-vector, else do not

Then clear the original vector when your are done and swap the in and out vector. Move the objects to (smart!)-pointers for improved efficiency (less copying going on).

For_each combined with creating a new vector should make this very robust against potential size changes and re-allocations that might occur when using std::vector.




回答3:


Sorry guys I changed the distance checking to the point of inserting...

vector<Point> rois;
for (int y = 0; y < result.rows; y++)
{
    for (int x = 0; x < result.cols; x++)
    {
        float qt = result.at<float>(y, x);

        if (qt >= threshVal)
        {
            Point A = Point(x, y);

            bool isNear = true;

            if (rois.size() > 0)
            {
                for (Point &P : rois)
                {
                    float distance = sqrt(pow(P.x - A.x, 2) + pow(P.y - A.y, 2) * 1.0);

                    if (distance < 10.0)
                    {
                        isNear = false;
                        break;
                    }
                }
                if (isNear)
                {
                    rois.push_back(A);
                }
            }
            else
            {
                rois.push_back(A);
            }
        }
    }
}

That is much more easier than the approach before.

But thanks for the answers.



来源:https://stackoverflow.com/questions/54038997/c-nested-for-loop-with-erasing-elements

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!