关于C++:如何通过索引从std :: vector <>中删除元素?

How do I erase an element from std::vector<> by index?

我有一个std::vector,我想删除第n个元素。我该怎么做?

1
2
3
4
5
6
7
std::vector<int> vec;

vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);

vec.erase(???);


要删除单个元素,可以执行以下操作:

1
2
3
4
5
6
7
8
std::vector<int> vec;

vec.push_back(6);
vec.push_back(-17);
vec.push_back(12);

// Deletes the second element (vec[1])
vec.erase(vec.begin() + 1);

或者,一次删除多个元素:

1
2
// Deletes the second through third elements (vec[1], vec[2])
vec.erase(vec.begin() + 1, vec.begin() + 3);


std::vector上的erase方法被重载,因此调用

1
vec.erase(vec.begin() + index);

当您只想删除一个元素时。


1
2
3
4
5
6
7
template <typename T>
void remove(std::vector<T>& vec, size_t pos)
{
    std::vector<T>::iterator it = vec.begin();
    std::advance(it, pos);
    vec.erase(it);
}


erase方法将以两种方式使用:

  • 删除单个元素:

    1
    vector.erase( vector.begin() + 3 ); // Deleting the fourth element
  • 删除元素范围:

    1
    vector.erase( vector.begin() + 3, vector.begin() + 5 ); // Deleting from fourth element to sixth element

  • 如果你有一个无序向量,你可以利用它无序的事实,使用我在CPPCON从丹·希金斯那里看到的东西。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    template< typename TContainer >
    static bool EraseFromUnorderedByIndex( TContainer& inContainer, size_t inIndex )
    {
        if ( inIndex < inContainer.size() )
        {
            if ( inIndex != inContainer.size() - 1 )
                inContainer[inIndex] = inContainer.back();
            inContainer.pop_back();
            return true;
        }
        return false;
    }

    由于列表顺序无关紧要,只需将列表中的最后一个元素复制到要删除的项的顶部,然后弹出并删除最后一个项。


    实际上,erase函数适用于两个配置文件:

    • 移除单个元素

      1
      iterator erase (iterator position);
    • 删除一系列元素

      1
      iterator erase (iterator first, iterator last);

    因为std::vec.begin()标记容器的开始,如果我们想删除向量中的ith元素,可以使用:

    1
    vec.erase(vec.begin() + index);

    如果仔细观察,vec.begin()只是一个指向向量起始位置的指针,向其添加i值会使指向i位置的指针递增,因此我们可以通过以下方式访问指向ith元素的指针:

    1
    &vec[i]

    所以我们可以写:

    1
    vec.erase(&vec[i]); // To delete the ith element


    如果您使用大向量(大小大于100000)并希望删除大量元素,我建议您执行以下操作:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    int main(int argc, char** argv) {

        vector <int> vec;
        vector <int> vec2;

        for (int i = 0; i < 20000000; i++){
            vec.push_back(i);}

        for (int i = 0; i < vec.size(); i++)
        {
            if(vec.at(i) %3 != 0)
                vec2.push_back(i);
        }

        vec = vec2;
        cout << vec.size() << endl;
    }

    代码将vec中不能被3除的每个数字复制到vec2。然后它在vec中复制vec2。速度相当快。要处理20000000个元素,此算法只需0.8秒!

    我用擦除方法做了同样的事情,它需要很多时间:

    1
    2
    3
    4
    Erase-Version (10k elements)  : 0.04 sec
    Erase-Version (100k elements) : 0.6  sec
    Erase-Version (1000k elements): 56   sec
    Erase-Version (10000k elements): ...still calculating (>30 min)


    要删除元素,请使用以下方法:

    1
    2
    3
    4
    5
    // declaring and assigning array1
    std:vector<int> array1 {0,2,3,4};

    // erasing the value in the array
    array1.erase(array1.begin()+n);

    有关更广泛的概述,请访问:http://www.cplusplus.com/reference/vector/vector/erase/


    这里还有一种方法可以做到这一点,如果你想删除一个元素,通过找到它在向量中的值,你只需要在向量上做这个。

    1
    2
    vector<int> ar(n);
    ar.erase(remove(ar.begin(), ar.end()), (place your value here from vector array));

    它将从这里移除您的值。谢谢


    前面的答案假设您总是有一个有符号的索引。遗憾的是,std::vector使用size_type进行索引,difference_type用于迭代器算术,因此如果启用了"-wconversion"和friends,它们就不能一起工作。这是回答问题的另一种方法,同时能够处理签名和未签名:

    移除:

    1
    2
    3
    4
    5
    6
    template<class T, class I, class = typename std::enable_if<std::is_integral::value>::type>
    void remove(std::vector<T> &v, I index)
    {
        const auto &iter = v.cbegin() + gsl::narrow_cast<typename std::vector<T>::difference_type>(index);
        v.erase(iter);
    }

    采取:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    template<class T, class I, class = typename std::enable_if<std::is_integral::value>::type>
    T take(std::vector<T> &v, I index)
    {
        const auto &iter = v.cbegin() + gsl::narrow_cast<typename std::vector<T>::difference_type>(index);

        auto val = *iter;
        v.erase(iter);

        return val;
    }