使用 for 循环擦除向量中的元素
Erase elements in vector using for loop
如何使用 for 循环按索引从向量中删除元素?我收到矢量超出范围错误。我在下面有一个示例代码。
vector<int> to_erase = {0, 1, 2};
vector<int> data = {3, 3, 3, 3};
for(int i = 0; i < to_erase.size(); i++) {
data.erase(data.begin() + to_erase[i]);
}
我认为这是因为我的向量的大小在每次迭代中都减小了,因此它无法访问索引 2。
在迭代的同时删除元素集合是不安全的,而且可能代价高昂。我建议每个符合您标准的元素在最后与一个元素交换。 (最后因为从最后擦除会更便宜。你可以跟踪你从向量的末尾回来了多少(基于交换的数量),并尽早打破我们的循环。现在基于你交换了多少元素你可以做这样的事情:
data.resize(data.size() - reverse_counter);
或
int pos = data.size() - reverse_counter;
data.erease(data.begin()+pos, data.end();
sudo代码只是为了说明思路。
如参考文献中所述,最后不擦除会导致重新分配,这是昂贵的。一些值得记住的事情:
http://www.cplusplus.com/reference/vector/vector/erase/
I think it is because the size of my vector reduces through every iteration
是的!
您可以通过保留一个额外的变量来实现,该变量计算被删除的元素,如下所示:
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> to_erase = {0, 1, 2};
vector<int> data = {3, 3, 3, 3};
int count_removed = 0;
for(unsigned int i = 0; i < to_erase.size(); i++)
data.erase(data.begin() + to_erase[i] - count_removed++);
for(unsigned int i = 0; i < data.size(); ++i)
cout << data[i] << "\n";
return 0;
}
输出:
3
我第一次用std::erase()
的时候遇到了同样的问题,好问题,+1.
我认为这是一个糟糕的设计,因为您将更改 for 循环不变量并且需要大量变通方法才能实现。无论如何,如果你真的想使用 for 循环,你 可以 标记你想要删除的内容和 运行 一个 stl remove_if,比如:
#include <iostream>
#include <vector>
#include <limits>
#include <algorithm>
using namespace std;
int main() {
vector<int> to_erase = {0, 1, 2};
vector<int> data = {3, 3, 3, 3};
cout << "Before:\n" ;
for(int i=0; i<data.size(); i++)
cout << i << "\t";
cout << endl;
for(int i=0; i<data.size(); i++)
cout << data[i] << "\t";
cout << endl;
for(int i = 0; i < to_erase.size(); i++) {
//data.erase(data.begin() + to_erase[i]);
data[i] = numeric_limits<int>::max();
}
data.erase(remove_if(data.begin(),
data.end(),
[](int i){return i==numeric_limits<int>::max();}), data.end());
cout << "Next:\n" ;
for(int i=0; i<data.size(); i++)
cout << i << "\t";
cout << endl;
for(int i=0; i<data.size(); i++)
cout << data[i] << "\t";
return 0;
}
您通常会使用 erase–remove idiom 来有效地从向量中删除多个元素(一个一个地删除它们通常效率较低,而且正如您所见,这并不总是微不足道的)。在其最一般的形式中,习语看起来像这样:
data.erase(remove_algorithm(begin(data), end(data)), end(data));
在您的情况下,remove_algorithm
基于另一个向量中的索引,因此我们也需要提供这些索引:
data.erase(
remove_indices(begin(data), end(data), begin(to_erase), end(to_erase)),
end(data));
不幸的是,标准库中不包含这样的算法。然而,写自己1:
是微不足道的
template <typename It, typename It2>
auto remove_indices(It begin, It end, It2 idx_b, It2 idx_e) -> It {
using idx_t = typename std::iterator_traits<It2>::value_type;
std::sort(idx_b, idx_e, std::greater<idx_t>{});
for (; idx_b != idx_e; ++idx_b) {
auto pos = begin + *idx_b;
std::move(std::next(pos), end--, pos);
}
return end;
}
这里,我们先将要剔除的指标从大到小排序。接下来,我们遍历这些索引。然后我们(最有效地)将当前位置(要删除)和向量末尾之间的所有元素向前移动一个。随后,末尾减一(以说明元素被删除的事实)。
1 *咳咳* 一旦你删除了代码中所有愚蠢的拼写错误。
如何使用 for 循环按索引从向量中删除元素?我收到矢量超出范围错误。我在下面有一个示例代码。
vector<int> to_erase = {0, 1, 2};
vector<int> data = {3, 3, 3, 3};
for(int i = 0; i < to_erase.size(); i++) {
data.erase(data.begin() + to_erase[i]);
}
我认为这是因为我的向量的大小在每次迭代中都减小了,因此它无法访问索引 2。
在迭代的同时删除元素集合是不安全的,而且可能代价高昂。我建议每个符合您标准的元素在最后与一个元素交换。 (最后因为从最后擦除会更便宜。你可以跟踪你从向量的末尾回来了多少(基于交换的数量),并尽早打破我们的循环。现在基于你交换了多少元素你可以做这样的事情:
data.resize(data.size() - reverse_counter);
或
int pos = data.size() - reverse_counter;
data.erease(data.begin()+pos, data.end();
sudo代码只是为了说明思路。
如参考文献中所述,最后不擦除会导致重新分配,这是昂贵的。一些值得记住的事情: http://www.cplusplus.com/reference/vector/vector/erase/
I think it is because the size of my vector reduces through every iteration
是的!
您可以通过保留一个额外的变量来实现,该变量计算被删除的元素,如下所示:
#include <iostream>
#include <vector>
using namespace std;
int main() {
vector<int> to_erase = {0, 1, 2};
vector<int> data = {3, 3, 3, 3};
int count_removed = 0;
for(unsigned int i = 0; i < to_erase.size(); i++)
data.erase(data.begin() + to_erase[i] - count_removed++);
for(unsigned int i = 0; i < data.size(); ++i)
cout << data[i] << "\n";
return 0;
}
输出:
3
我第一次用std::erase()
的时候遇到了同样的问题,好问题,+1.
我认为这是一个糟糕的设计,因为您将更改 for 循环不变量并且需要大量变通方法才能实现。无论如何,如果你真的想使用 for 循环,你 可以 标记你想要删除的内容和 运行 一个 stl remove_if,比如:
#include <iostream>
#include <vector>
#include <limits>
#include <algorithm>
using namespace std;
int main() {
vector<int> to_erase = {0, 1, 2};
vector<int> data = {3, 3, 3, 3};
cout << "Before:\n" ;
for(int i=0; i<data.size(); i++)
cout << i << "\t";
cout << endl;
for(int i=0; i<data.size(); i++)
cout << data[i] << "\t";
cout << endl;
for(int i = 0; i < to_erase.size(); i++) {
//data.erase(data.begin() + to_erase[i]);
data[i] = numeric_limits<int>::max();
}
data.erase(remove_if(data.begin(),
data.end(),
[](int i){return i==numeric_limits<int>::max();}), data.end());
cout << "Next:\n" ;
for(int i=0; i<data.size(); i++)
cout << i << "\t";
cout << endl;
for(int i=0; i<data.size(); i++)
cout << data[i] << "\t";
return 0;
}
您通常会使用 erase–remove idiom 来有效地从向量中删除多个元素(一个一个地删除它们通常效率较低,而且正如您所见,这并不总是微不足道的)。在其最一般的形式中,习语看起来像这样:
data.erase(remove_algorithm(begin(data), end(data)), end(data));
在您的情况下,remove_algorithm
基于另一个向量中的索引,因此我们也需要提供这些索引:
data.erase(
remove_indices(begin(data), end(data), begin(to_erase), end(to_erase)),
end(data));
不幸的是,标准库中不包含这样的算法。然而,写自己1:
是微不足道的template <typename It, typename It2>
auto remove_indices(It begin, It end, It2 idx_b, It2 idx_e) -> It {
using idx_t = typename std::iterator_traits<It2>::value_type;
std::sort(idx_b, idx_e, std::greater<idx_t>{});
for (; idx_b != idx_e; ++idx_b) {
auto pos = begin + *idx_b;
std::move(std::next(pos), end--, pos);
}
return end;
}
这里,我们先将要剔除的指标从大到小排序。接下来,我们遍历这些索引。然后我们(最有效地)将当前位置(要删除)和向量末尾之间的所有元素向前移动一个。随后,末尾减一(以说明元素被删除的事实)。
1 *咳咳* 一旦你删除了代码中所有愚蠢的拼写错误。