根据向量大小擦除 for 循环内 std::vector 的索引 [英] Erasing indices of std::vector inside a for loop based on vector size

查看:81
本文介绍了根据向量大小擦除 for 循环内 std::vector 的索引的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一个函数来过滤掉 std::vector 中我不喜欢的元素,在这种情况下是一个 opencv 轮廓向量.下面的代码看起来可以工作,但它不起作用,我怀疑这是因为每当我擦除索引时索引都会改变,但是我继续下一个 i 值迭代.

I've created a function to filter out the elements I don't like in a std::vector, in this case a vector of opencv contours. The code below looks like it would work, however it does not and I suspect it is because the indices are changed whenever I erase the indices, however I continue to the next i value iteration.

void FilterContours( std::vector<std::vector<cv::Point>> contours )
{
    for ( int i = 0; i < contours.size(); i++ ) {

        //Remove contours smaller than 5 from vector - example
        if ( contours[i].size() < 5 ) {
            contours.erase(contours.begin() + i);
            continue;
        }

        //Other filtering...
    }
    return;
}

所以问题是,这会按预期工作吗(我认为不会),如果没有,我该如何让它按预期工作?我应该在擦除后添加 i -= 1 以保持正确的索引位置吗?

So the question is, would this work as intended (I don't think it does), and if not, how do I make it work as intended? Should I add a i -= 1 after the erase to maintain the correct index position?

推荐答案

每次从容器中erase() 一个元素,它的 size() 递减,并且其余元素的索引也递减.但是你无条件地增加你的循环计数器,所以每次你删除一个元素时,你跳过跟随它的下一个元素!

Each time you erase() an element from a container, its size() decrements, and the indexes of the remaining elements are decremented as well. But you are incrementing your loop counter unconditionally, so every time you erase an element, you skip the next element that had followed it!

此外,您正在按值传递 vector,因此您正在对 vectorcopy 进行操作,并且调用者将看不到原始 vector 的任何变化.

Also, you are passing your vector by-value, so you are operating on a copy of the vector, and the caller will not see any changes in the original vector.

正确的做法是:

  1. 仅当元素未被擦除时才在循环体内增加索引变量.删除元素时保持变量不变:

  1. increment your index variable inside of the loop body only when an element is NOT erased. Leave the variable as-is when you DO erase an element:

void FilterContours( std::vector<std::vector<cv::Point>> &contours )
{
    int i = 0;
    while ( i < contours.size() ) {
        if ( contours[i].size() < 5 ) {
            contours.erase(contours.begin() + i);
            continue;
        }

        //Other filtering...

        ++i;
    }
}

  • 使用迭代器代替索引:

  • use iterators instead of indexes:

    void FilterContours( std::vector<std::vector<cv::Point>> &contours )
    {
        auto it = contours.begin();
        while ( it != contours.end() ) {
            if ( it->size() < 5 ) {
                it = contours.erase(it);
                continue;
            }
    
            //Other filtering...
    
            ++it;
        }
    }
    

  • 使用 erase-remove 习惯用法:

    void FilterContours( std::vector<std::vector<cv::Point>> &contours )
    {
        contours.erase(
            std:::remove_if(
                contours.begin(),
                contours.end(),
                [](const std::vector<cv::Point> &v)
                {
                    if (v.size() < 5) return true; 
                    //Other filtering...
                    return false;
                }
            ),
            contours.end()
        );
    }
    

  • 这篇关于根据向量大小擦除 for 循环内 std::vector 的索引的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆