代码之家  ›  专栏  ›  技术社区  ›  bradtgmurray

如何从stl向量中移除具有特定值的项?

  •  122
  • bradtgmurray  · 技术社区  · 17 年前

    我正在查看stl vector的API文档,注意到vector类上没有允许删除具有特定值的元素的方法。这似乎是一种常见的操作,但奇怪的是,没有内置的方法来实现这一点。

    9 回复  |  直到 17 年前
        1
  •  171
  •   roschach    7 年前

    std::remove 实际上不会从容器中删除元素,但它会返回可以传递给的新的结束迭代器 container_type::erase 要真正删除容器末尾的额外元素,请执行以下操作:

    std::vector<int> vec;
    // .. put in some values ..
    int int_to_remove = n;
    vec.erase(std::remove(vec.begin(), vec.end(), int_to_remove), vec.end());
    
        2
  •  73
  •   Etherealone    11 年前

    如果要删除 项目中,以下内容将更有效率。

    std::vector<int> v;
    
    
    auto it = std::find(v.begin(), v.end(), 5);
    if(it != v.end())
        v.erase(it);
    

    或者,如果订单对您不重要,您可以避免移动项目的开销:

    std::vector<int> v;
    
    auto it = std::find(v.begin(), v.end(), 5);
    
    if (it != v.end()) {
      using std::swap;
    
      // swap the one to be removed with the last element
      // and remove the item at the end of the container
      // to prevent moving all items after '5' by one
      swap(*it, v.back());
      v.pop_back();
    }
    
        3
  •  15
  •   bradtgmurray    17 年前

    使用全局方法std::remove和begin和end迭代器,然后使用std::vector.erase实际删除元素。

    文档链接
    删除 http://www.cppreference.com/cppalgorithm/remove.html
    std::vector.erase http://www.cppreference.com/cppvector/erase.html

    std::vector<int> v;
    v.push_back(1);
    v.push_back(2);
    
    //Vector should contain the elements 1, 2
    
    //Find new end iterator
    std::vector<int>::iterator newEnd = std::remove(v.begin(), v.end(), 1);
    
    //Erase the "removed" elements.
    v.erase(newEnd, v.end());
    
    //Vector should now only contain 2
    

        4
  •  6
  •   Pavan Chandaka    7 年前

    从…起 c++20 :

    引入了一个非成员函数 std::erase ,它将要删除的向量和值作为输入。

    前任:

    std::vector<int> v = {90,80,70,60,50};
    std::erase(v,50);
    
        5
  •  5
  •   Luke Halliwell    17 年前

    如果您正在密集地执行此操作,那么出于这个原因,应该考虑使用std::set。

        6
  •  5
  •   frogatto    9 年前

    如果有一个未排序的向量,那么可以简单地与最后一个向量元素交换 resize()

    有了一个订购的集装箱,你最好带上它 std::vector::erase() . 请注意,有一个 std::remove() 定义于 <algorithm>

        7
  •  3
  •   jhasse    8 年前

    一个较短的解决方案(不会强迫您重复向量名称4次)是使用Boost:

    #include <boost/range/algorithm_ext/erase.hpp>
    
    // ...
    
    boost::remove_erase(vec, int_to_remove);
    

    看见 http://www.boost.org/doc/libs/1_64_0/libs/range/doc/html/range/reference/algorithms/new/remove_erase.html

        8
  •  3
  •   Remindme Xavier Nodet    6 年前

    另见 std::remove_if

    下面是上面链接中的示例:

    vector<int> V;
    V.push_back(1);
    V.push_back(4);
    V.push_back(2);
    V.push_back(8);
    V.push_back(5);
    V.push_back(7);
    
    copy(V.begin(), V.end(), ostream_iterator<int>(cout, " "));
        // The output is "1 4 2 8 5 7"
    
    vector<int>::iterator new_end = 
        remove_if(V.begin(), V.end(), 
                  compose1(bind2nd(equal_to<int>(), 0),
                           bind2nd(modulus<int>(), 2)));
    V.erase(new_end, V.end()); [1]
    
    copy(V.begin(), V.end(), ostream_iterator<int>(cout, " "));
        // The output is "1 5 7".
    
        9
  •  2
  •   Harshad Sharma    6 年前

    *

    C++社区已经听到了你的请求:

    C++ 20 现在提供了一种简单的方法。 它变得非常简单:

    #include <vector>
    ...
    vector<int> cnt{5, 0, 2, 8, 0, 7};
    std::erase(cnt, 0);
    

    你应该退房 std::erase std::erase_if .

    它不仅会删除值的所有元素(此处为“0”),而且还会在 O(n) 时间复杂性。这是你能得到的最好的。

    erase-remove idiom :

    #include <algorithm>
    ...
    vec.erase(std::remove(vec.begin(), vec.end(), 0), vec.end());
    
        10
  •  0
  •   Katianie    8 年前

    如果您想在没有任何额外费用的情况下完成此操作,请包括:

    vector<IComponent*> myComponents; //assume it has items in it already.
    void RemoveComponent(IComponent* componentToRemove)
    {
        IComponent* juggler;
    
        if (componentToRemove != NULL)
        {
            for (int currComponentIndex = 0; currComponentIndex < myComponents.size(); currComponentIndex++)
            {
                if (componentToRemove == myComponents[currComponentIndex])
                {
                    //Since we don't care about order, swap with the last element, then delete it.
                    juggler = myComponents[currComponentIndex];
                    myComponents[currComponentIndex] = myComponents[myComponents.size() - 1];
                    myComponents[myComponents.size() - 1] = juggler;
    
                    //Remove it from memory and let the vector know too.
                    myComponents.pop_back();
                    delete juggler;
                }
            }
        }
    }
    
        11
  •  0
  •   DecPK    7 年前

    有两种方法可以用来删除项目。

    std :: vector < int > v;
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);
    v.push_back(40);
    v.push_back(40);
    v.push_back(50);
    

    1) 非有效方式: 虽然它看起来相当有效,但这并不是因为擦除函数删除元素并将所有元素向左移动1。 所以它的复杂度是O(n^2)

    std :: vector < int > :: iterator itr = v.begin();
    int value = 40;
    while ( itr != v.end() )
    {
       if(*itr == value)
       { 
          v.erase(itr);
       }
       else
           ++itr;
    }
    

    2) 有效方式(推荐) 删除-删除习惯用法 .

    • remove将给定的范围转换为一个范围,其中比较的所有元素都不等于给定元素,并移动到容器的开头。
    • 所以,实际上不要删除匹配的元素。 它只是将不匹配项移到起始位置,并将迭代器移到新的有效结束位置。 它只需要O(n)复杂度。

    移除算法的输出为:

    10 20 30 50 40 50 
    

    因为remove的返回类型是该范围新端的迭代器。

    template <class ForwardIterator, class T>
      ForwardIterator remove (ForwardIterator first, ForwardIterator last, const T& val);
    

    v.erase ( std :: remove (v.begin() , v.end() , element ) , v.end () );
    

    所以这个方法在O(n)中有效