我有一张地图。我们说map<int, vector<int> > mymap1
。
我想通过删除一些“键”来更新mymap1,并从所选键的向量部分删除不需要的“元素”。要删除的“密钥”或“元素”是从另一个向量中提供的,称为“mylabel”。实际上,我需要在地图中保留的是标签等于1的值。(最后,键必须包含标签为1的元素。)
我已经实现了这个(参见下面的代码),但是遇到了一些编译器错误。
map<int, vector<int> > mymap1;
map<int, vector<int> >::iterator map1;
for (map1=mymap1.begin();map1!=mymap1.end();map1++){
int key = map1->first;
if (mylabel[key].Label() != 1){ mymap1.erase(key);
}
else{
vector<int> &myvec = map1->second;
for (vector<int>::iterator rn=myvec.begin(); rn!=myvec.end(); rn++){
if (mylabel[*rn].Label() != 1) myvec.erase(myvec.begin()+(*rn));
}
}
}
为了得到一个想法,我正在展示我的地图的一些例子。
0 1 2 6 10
1 0 2 4 3 6
2 0 1 3 5 8
3 1 2 4 5 7
4 1 3 6 7
5 2 3 8 7 9
6 1 0 7 4
7 6 4 3 5 9 11 10 13 12
8 2 5 9 11 18 15 19 20 22
9 5 7 11 8
10 0 7 14 16
11 9 7 8 13
12 7 13 14
13 7 12 11 14 15
14 12 10 16 13 15 17
15 13 14 8 17 19
16 14 10 17 21
17 14 16 15 21 18
18 8 20 19 17 26 27
19 8 15 18
20 8 18
21 16 17 23 24
22 8
23 25 21 24 26
24 23 21
25 23 26
26 23 25 18
27 18 28
28 27
如果我告诉你我的mylabel,它如下。
for(int c=0;c<mylabel.size();c++){
cout<<c<<" : "<<"label "<<mylabel[c].Label()<<endl;
}
0 : label 0
1 : label 0
2 : label 0
3 : label 0
4 : label 0
5 : label 1
6 : label 0
7 : label 1
8 : label 0
9 : label 1
10 : label 0
11 : label 1
12 : label 0
13 : label 0
14 : label 1
15 : label 1
16 : label 1
17 : label 1
18 : label 0
19 : label 0
20 : label 0
21 : label 1
22 : label 0
23 : label 0
24 : label 0
25 : label 1
26 : label 1
27 : label 0
28 : label 0
当我停用else部分并运行上面的代码时,我得到了一个输出。但是,我想说你这是一个错误的结果。我得到了应删除的额外密钥。我无法弄清楚为什么我得到了这个错误的结果。 如果我显示我得到的钥匙清单,
5
7
9
11
14
15
16
17
20 - wrong
21
24 - wrong
25
26
你可以帮我纠正我的代码,以获得我修改后的地图。提前谢谢。
答案 0 :(得分:2)
您的擦除逻辑错误,最终使用无效的迭代器。 (如果你擦除迭代器然后继续使用那个迭代器,那么你真的会从脚下拉出地毯。)
对于基于节点的容器(列表,映射,设置,无序),通常擦除如下:
for (auto it = c.begin(); it != c.end(); )
{
if (must_delete(*it)) // or it->first
{
c.erase(it++); // advance first, then erase previous
}
else
{
++it;
}
}
(这种模式是我最喜欢的修复后增量运算符的理由。)
对于连续的容器(vector,deque),一次擦除一个元素是低效的,因为它会导致重复移动。这里首选的习惯是“删除/擦除”,但如果您不想直接删除元素值,则需要提供合适的谓词。这是lambdas的一个例子,为简洁起见:
std::vector<int> v;
v.erase(std::remove_if(v.begin(), v.end(),
[](int n)->bool{return some_criterion(n);}),
v.end());
在您的情况下,您可以将lambda写为[mylabel&](n)->bool{ return mylabel[n].Label() != 1; }
;如果你没有lambda,那就写一个传统的谓词对象:
struct LabelFinder
{
LabelFinder(const LabelVector & lv) : label(lv) { }
inline bool operator()(int n) const
{
return label[n].Label() != 1;
}
private:
const LabelVector & label;
};
现在使用:
v.erase(std::remove_if(v.begin(), v.end(), LabelFinder(mylabel)), v.end());
答案 1 :(得分:1)
问题出在for
循环中。 std::vector<T>::erase()
将迭代器返回到新位置,后跟已擦除的项目。所以循环应该写成:
for (vector<int>::iterator rn=myvec.begin(); rn!=myvec.end();)
{
if (mylabel[*rn].Label() != 1)
rn = myvec.erase(rn);
else
++rn;
}
阅读文档:
顺便说一句,我对此表示怀疑:
rn = myvec.erase(myvec.begin()+(*rn));
Vs
rn = myvec.erase(rn);
你确定要第一个吗?
擦除不等于1的元素的惯用方法是:
//Define this function
bool isNotOne(int n) { return n != 1; }
//then do this instead of writing manual loop
myvec.erase( remove_if(myvec.begin(), myvec.end(), isNotOne), myvec.end() );
这叫做: