如何按值从vector中删除元素,但只能删除该值的单个实例

How to remove element from vector by value but only single instance of that value?

本文关键字:删除 实例 单个 何按值 vector 元素      更新时间:2023-10-16

问题在这里,

我有一个向量,我需要从向量中一个接一个地删除2个元素。我知道这两个元素的值以及它们的索引

首先,我试图删除这两个元素使用索引,即

v.erase(v.begin()+index1);
v.erase(v.begin()+index2);

但问题是擦除第一个元素后,数组中第二个元素的索引发生了变化。

因此,我尝试按值删除它们,即

v.erase(remove(v.begin(),v.end(),value),v.end());

但是这会删除该值的所有实例(例如,如果有两个"1",它会删除它们两个),而我只想删除一个元素。

如何解决?

当您从std::vector<>中删除元素时,位于擦除点或擦除点之后的任何迭代器都无效。

这就是为什么你必须先删除位于索引较大位置的元素。

例子:

using namespace std;
int main() 
{
  vector<int> v { 1, 2, 3, 4, 5, 6, 7};
  size_t index1 = 3; // We want to remove 4
  size_t index2 = 5; // We want to remove 6
  v.erase(begin(v) + index2); // We remove the element with the greater index first
  v.erase(begin(v) + index1); // fine, v.begin() + index1 is BEFORE the previous point of erasure
  for(auto val : v)
    cout << val << " ";
  return 0;
}

编辑:

  • 这是一个通用算法,remove_at_indexes,用于通过指定索引的形式从容器中删除元素(std::size_t)
  • 它将工作在任何STL兼容的容器(vector, string, deque…)

代码:

template<class Iterator, class IteratorId>
Iterator remove_at_indexes(Iterator first, Iterator last, IteratorId indexes_begin, IteratorId indexes_end)
{
    std::sort(indexes_begin, indexes_end, std::less<size_t>());
    std::size_t count { 0 };
    if (first != last)
        for(auto i = first; i != last; i++)
            if(indexes_begin == indexes_end)
               first++;
            else
            {
                if (count != *indexes_begin)
                    *first++ = std::move(*i);
                else
                    indexes_begin++;
                count++;
            }
    return first;
}

用法示例:

  vector<int> v { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
  vector<size_t> indexes { 4, 1, 9 };
  v.erase(remove_at_indexes(v.begin(), v.end(), indexes.begin(), indexes.end()), v.end());
输出:

1 3 4 6 7 8 9

演示。

您可以使用:

v.erase(v.begin() + std::max(index1, index2));
v.erase(v.begin() + std::min(index1, index2));

或者

auto indexes = std::minmax(index1, index2);
v.erase(v.begin() + indexes.second);
v.erase(v.begin() + indexes.first);