我正在使用C ++,我有一个配对变量的向量,第一个元素是一个向量,第二个元素是一个整数。我的问题是我试图从这个向量中删除某些元素,似乎无法让它工作!
代码如下所示,一切正常,因为我期待这一行:
vec1.erase(i);
因为我可以将一些其他相关变量从矢量传递到屏幕,它们是正确的。
compareVecs只是该类的一个元素,用于比较一些变量。
void myCode::PairRemoval(vector<myTypeDef> &vec1, const vector<myTypeDef> &vec2, double conditionMax) {
bool condition=false;
for (unsigned int i=0; i<vec1.size(); i++){
for (unsigned int j=0; j<vec2.size(); j++){
if (vec1[i].first.compareVecs(vec2[j].first) <= conditionMax) {
condition = true;
break;
}
}
if (condition) {
vec1.erase(i);
cout<<"removed"<<endl;
}
}
}
如果满足条件,我希望从该向量中删除该对。
提前感谢您的帮助!
答案 0 :(得分:3)
erase的问题在于它会删除你指向的元素,同时也会改变向量的大小。由于向量要求每个后续元素都被向下复制,因此效率非常低。因此,如果您有15个元素并擦除第一个元素,那么您现在只需复制14个元素。
您可以使用
来解决这个问题for(vector<whatever>::iterator foo = myVector.begin(); foo != myVector.end(); ++foo){
if( myPredicate( foo ) ){
foo = myVector.erase(foo);
}
}
但正如我所说,这是非常低效的。如果需要擦除每个元素,则可能需要O(N ^ 2)时间。
相反,请使用复制和交换技术:
vector<T> myNewVector;
copy_if( myOldVector.begin(), myOldVector.end(), back_inserter(myNewVector), fun_ptr(myPredicate) );
myOldVector.swap(myNewVector);
答案 1 :(得分:2)
您不应在循环内迭代向量和擦除元素。擦除元素时,矢量大小会更改,索引也会更改。推荐的方法是将你必须删除的元素存储在另一个结构中(如矢量),然后循环删除它们。
void myCode::PairRemoval(vector<myTypeDef> &vec1, const vector<myTypeDef> &vec2, double conditionMax) {
bool condition=false;
vector<vector<myTypeDef>::iterator> toRemove;
for (vector<myTypeDef>::iterator it = vec1.begin(); it != vec1.end(); it++){
for (unsigned int j=0; j<vec2.size(); j++){
if ((*it).first.compareVecs(vec2[j].first) <= conditionMax) {
condition = true;
break;
}
}
if (condition) {
toRemove.push_back(it);
}
}
for(int i = 0; i < toRemove.size(); i++){
vec1.erase(toRemove[i]);
}
}
答案 2 :(得分:2)
标准库已经包含一个函数[template],用于根据自定义谓词从序列中删除元素,因此可以更清楚地将“条件”抽象为仿函数并使用标准的擦除/删除习惯用法。
这个示例编译但我无法给仿函数一个有意义的名称,因为我不确定你的条件逻辑背后的基本原理是什么。
#include <vector>
#include <algorithm>
struct x { double compareVecs( const x& ) const; };
typedef std::pair<x, int> myTypeDef;
class ErasePredicate
{
public:
ErasePredicate(const std::vector<myTypeDef>& vec2, double conditionMax)
: _vec2(&vec2), _conditionMax(conditionMax) {}
// The valuable condition logic goes here
bool operator()( const myTypeDef& v ) const // assume this can be const ref
{
for (size_t j = 0; j != _vec2->size(); ++j)
{
if (v.first.compareVecs((*_vec2)[j].first) <= _conditionMax)
{
return true;
}
}
return false;
}
private:
// pointer, to get copy-ctor and op= for free
const std::vector<myTypeDef>* _vec2;
double _conditionMax;
};
void PairRemoval(std::vector<myTypeDef> &vec1,
const std::vector<myTypeDef> &vec2,
double conditionMax)
{
// The mechanics of performing the erase is handled by stdlib functionality
vec1.erase(std::remove_if(vec1.begin(),
vec1.end(),
ErasePredicate(vec2, conditionMax)),
vec1.end());
}
答案 3 :(得分:1)
我认为你的for循环存在缺陷。假设我是5并且您删除元素5.然后我将增加到6以进行下一次迭代。但是现在元素6的元素现在位于第5位。这意味着你的循环不会擦除向量中的后续元素。
作为一种解决方法,在从向量中删除元素后减少i。
答案 4 :(得分:1)
通过引用c++ reference,我认为erase应该以迭代器作为参数。也许你的代码应该是vec1.erase(vec1.begin()+ i);
答案 5 :(得分:0)
看起来您想要从容器中删除一些元素。 C ++标准库只有一个算法:std::remove。唯一需要注意的是它不会从容器中移除任何东西:)
如果可以使用简单的运算符==标识要删除的元素,则可以使用std::remove
。如果识别元素更复杂,则需要使用std::remove_if
。
现在请注意。在C ++标准库中,算法与容器分离。 std::remove
需要几个迭代器,因此它可能会破坏这些迭代器之间的元素,但它对容器一无所知,因此无法更改它。解决方案是erase-remove idiom。
auto it = std::remove_if( v.begin(), v.end(), some_predicate_returning_bool());
myOldVector.erase(it, v.end()); // or a lambda^
首先,我们使用remove
将“未删除的”元素移动到容器的开头。 remove
返回一个迭代器,它指向我们不想要的第一个元素。
std::vector<int> v { 1, 3, 3, 7 };
auto it = std::remove(v.begin(), v.end(), 3);
此次通话后,v将包含1, 7, 3, 7
和it
点,而不是7
。 (1保留了它的位置,7在它后面洗牌)。调用
v.erase(it, v.end());
导致v
成为1, 7
。