简体   繁体   English

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

[英]How do I remove an item from a stl vector with a certain value?

I was looking at the API documentation for stl vector, and noticed there was no method on the vector class that allowed the removal of an element with a certain value.我正在查看 stl 矢量的 API 文档,并注意到矢量类上没有允许删除具有特定值的元素的方法。 This seems like a common operation, and it seems odd that there's no built in way to do this.这似乎是一种常见的操作,而且没有内置的方法来做到这一点似乎很奇怪。

std::remove does not actually erase elements from the container: it moves the elements to be removed to the end of the container, and returns the new end iterator which can be passed to container_type::erase to do the actual removal of the extra elements that are now at the end of the container: 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());

If you want to remove an item, the following will be a bit more efficient.如果你想删除一个项目,下面会更有效率。

std::vector<int> v;


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

or you may avoid overhead of moving the items if the order does not matter to you:或者,如果订单对您无关紧要,您可以避免移动物品的开销:

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();
}

Use the global method std::remove with the begin and end iterator, and then use std::vector.erase to actually remove the elements.使用带有 begin 和 end 迭代器的全局方法 std::remove,然后使用 std::vector.erase 实际删除元素。

Documentation links文档链接
std::remove http://www.cppreference.com/cppalgorithm/remove.html std::remove http://www.cppreference.com/cppalgorithm/remove.html
std::vector.erase http://www.cppreference.com/cppvector/erase.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

Thanks to Jim Buck for pointing out my error.感谢 Jim Buck 指出我的错误。

From c++20 :c++20开始:

A non-member function introduced std::erase , which takes the vector and value to be removed as inputs.一个非成员函数引入了std::erase ,它将要删除的向量和值作为输入。

ex:前任:

std::vector<int> v = {90,80,70,60,50};
std::erase(v,50);

If you have an unsorted vector, then you can simply swap with the last vector element then resize() .如果你有一个未排序的向量,那么你可以简单地与最后一个向量元素交换,然后resize()

With an ordered container, you'll be best off with ‍ std::vector::erase() .使用有序容器,最好使用std::vector::erase() Note that there is a std::remove() defined in <algorithm> , but that doesn't actually do the erasing.请注意,在<algorithm>中定义了一个std::remove() ,但这实际上并没有进行擦除。 (Read the documentation carefully). (仔细阅读文档)。

The other answers cover how to do this well, but I thought I'd also point out that it's not really odd that this isn't in the vector API: it's inefficient, linear search through the vector for the value, followed by a bunch of copying to remove it.其他答案涵盖了如何做好这一点,但我想我还想指出,这不在向量 API 中并不奇怪:它是低效的,通过向量线性搜索值,然后是一堆复制以将其删除。

If you're doing this operation intensively, it can be worth considering std::set instead for this reason.如果您正在密集地执行此操作,则可能值得考虑 std::set 出于这个原因。

* *

C++ community has heard your request :) C++ 社区已经听到了您的请求 :)

* *

C++ 20 provides an easy way of doing it now. C++ 20现在提供了一种简单的方法。 It gets as simple as :它变得如此简单:

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

You should check out std::erase and std::erase_if .您应该检查std::erasestd::erase_if

Not only will it remove all elements of the value (here '0'), it will do it in O(n) time complexity.它不仅会删除值的所有元素(此处为“0”),而且会以O(n)的时间复杂度进行。 Which is the very best you can get.这是你能得到的最好的。

If your compiler does not support C++ 20, you should use erase-remove idiom :如果你的编译器不支持 C++ 20,你应该使用erase-remove idiom

#include <algorithm>
...
vec.erase(std::remove(vec.begin(), vec.end(), 0), vec.end());

See also std::remove_if to be able to use a predicate...另请参阅std::remove_if以能够使用谓词...

Here's the example from the link above:这是上面链接中的示例:

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".

A shorter solution (which doesn't force you to repeat the vector name 4 times) would be to use Boost:一个更短的解决方案(不会强迫您重复向量名称 4 次)是使用 Boost:

#include <boost/range/algorithm_ext/erase.hpp>

// ...

boost::remove_erase(vec, int_to_remove);

See http://www.boost.org/doc/libs/1_64_0/libs/range/doc/html/range/reference/algorithms/new/remove_erase.html请参阅http://www.boost.org/doc/libs/1_64_0/libs/range/doc/html/range/reference/algorithms/new/remove_erase.html

Two ways are there by which you can use to erase an item particularly.有两种方法可以用来特别擦除一个项目。 lets take a vector让我们拿一个向量

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) Non efficient way : Although it seems to be quite efficient but it's not because erase function delets the elements and shifts all the elements towards left by 1. so its complexity will be O(n^2) 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) Efficient way ( RECOMMENDED ) : It is also known as ERASE - REMOVE idioms . 2)高效方式(推荐) :也称为ERASE-REMOVE成语

  • std::remove transforms the given range into a range with all the elements that compare not equal to given element shifted to the start of the container. std::remove 将给定范围转换为一个范围,其中所有比较不等于给定元素的元素都移动到容器的开头。
  • So, actually don't remove the matched elements.所以,实际上不要删除匹配的元素。 It just shifted the non matched to starting and gives an iterator to new valid end.它只是将不匹配的内容转移到开始并将迭代器提供给新的有效结束。 It just requires O(n) complexity.它只需要 O(n) 复杂度。

output of the remove algorithm is :删除算法的输出是:

10 20 30 50 40 50 

as return type of remove is iterator to the new end of that range.因为 remove 的返回类型是指向该范围新端的迭代器。

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

Now use vector's erase function to delete elements from the new end to old end of the vector.现在使用向量的擦除功能从向量的新端到旧端删除元素。 It requires O(1) time.它需要 O(1) 时间。

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

so this method work in O(n)所以这个方法在 O(n) 中工作

Similar to the erase remove idiom , for vector one could use resize and remove and use iterator distance computation:擦除删除习语类似,对于vector ,可以使用resizeremove并使用迭代器距离计算:

std::vector<int> vec;
// .. put in some values ..
int int_to_remove = n;
vec.resize(std::remove(vec.begin(), vec.end(), int_to_remove) - vec.begin());

Tested here .在这里测试。

If you want to do it without any extra includes:如果您想在没有任何额外内容的情况下执行此操作,则包括:

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;
            }
        }
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM