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

发布于 2024-07-04 20:09:01 字数 89 浏览 6 评论 0原文

我正在查看 stl 矢量的 API 文档,并注意到矢量类上没有允许删除具有特定值的元素的方法。 这似乎是一个常见的操作,并且没有内置的方法来执行此操作似乎很奇怪。

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. This seems like a common operation, and it seems odd that there's no built in way to do this.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(12

夏日浅笑〃 2024-07-11 20:09:01

如果你想在没有任何额外内容的情况下做到这一点:

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

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;
            }
        }
    }
}
羞稚 2024-07-11 20:09:01

类似于擦除删除惯用语,用于向量 可以使用 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());

经过测试 此处

Similar to the erase remove idiom, for vector one could use resize and remove and use iterator distance computation:

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.

茶花眉 2024-07-11 20:09:01

一个更短的解决方案(不会强迫您重复向量名称 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

A shorter solution (which doesn't force you to repeat the vector name 4 times) would be to use 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

淡墨 2024-07-11 20:09:01

有两种方法可以用来专门删除某个项目。
让我们取一个向量

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) 高效方法(推荐):也称为ERASE - REMOVE idioms em>。

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

删除算法的输出是:

10 20 30 50 40 50 

因为删除的返回类型是到该范围的新末尾的迭代器。

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

现在使用向量的擦除函数删除向量新端到旧端的元素。 需要 O(1) 时间。

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

所以这个方法的工作时间复杂度为 O(n)

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)

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 .

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

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.

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.

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

so this method work in O(n)

秋心╮凉 2024-07-11 20:09:01

*

C++ 社区已听到您的请求:)

*

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

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

您应该查看 std::erasestd::erase_if

它不仅会删除该值的所有元素(此处为“0”),而且会以 O(n) 时间复杂度完成此操作。 这是你能得到的最好的。

如果您的编译器不支持 C++ 20,则应使用 erase-remove idiom:

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

*

C++ community has heard your request :)

*

C++ 20 provides an easy way of doing it now.
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.

Not only will it remove all elements of the value (here '0'), it will do it in O(n) time complexity. Which is the very best you can get.

If your compiler does not support C++ 20, you should use erase-remove idiom:

#include <algorithm>
...
vec.erase(std::remove(vec.begin(), vec.end(), 0), vec.end());
白芷 2024-07-11 20:09:01

另请参阅 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".

See also std::remove_if to be able to use a predicate...

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".
夜血缘 2024-07-11 20:09:01

c++20开始:

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

前任:

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

From c++20:

A non-member function introduced std::erase, which takes the vector and value to be removed as inputs.

ex:

std::vector<int> v = {90,80,70,60,50};
std::erase(v,50);
亢潮 2024-07-11 20:09:01

其他答案涵盖了如何做好这一点,但我想我还要指出,这不在向量 API 中并不奇怪:它是低效的,通过向量线性搜索值,然后是一堆复制以将其删除。

如果您密集地执行此操作,出于这个原因,可能值得考虑使用 std::set 。

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.

If you're doing this operation intensively, it can be worth considering std::set instead for this reason.

世界和平 2024-07-11 20:09:01

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

对于有序容器,您最好使用 ‍std::vector::erase()。 请注意, 中定义了 std::remove(),但实际上并没有执行擦除操作。 (仔细阅读文档)。

If you have an unsorted vector, then you can simply swap with the last vector element then resize().

With an ordered container, you'll be best off with ‍std::vector::erase(). Note that there is a std::remove() defined in <algorithm>, but that doesn't actually do the erasing. (Read the documentation carefully).

世界和平 2024-07-11 20:09:01

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

文档链接
std::remove 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

感谢 Jim Buck 指出我的错误。

Use the global method std::remove with the begin and end iterator, and then use std::vector.erase to actually remove the elements.

Documentation links
std::remove 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

Thanks to Jim Buck for pointing out my error.

ㄟ。诗瑗 2024-07-11 20:09:01

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

std::remove does not actually erase elements from the container: it overwrites the elements that should not be removed at the beginning of the container, and returns the iterator pointing to the next element after them. This iterator 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::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());
把梦留给海 2024-07-11 20:09:01

如果您想删除一个项目,下面的方法会更有效一些。

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

这就是 Jim 的 std::vector::erase + std::remove 方法在幕后做的。

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

Which is what Jim's method of std::vector::erase + std::remove does under the hood.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文