通过删除一些键和一些元素来更新映射的问题
problem with updating a map by removing some keys and also some elements
我有一张地图。假设是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
你能帮我纠正我的代码,以便得到我修改后的地图吗?
您的擦除逻辑是错误的,您最终使用了无效的迭代器。(如果你删除一个迭代器,然后继续使用它,你实际上是在把地毯从你的脚下拉出来。)
对于基于节点的容器(list、map、set、unordered),通常按如下方式擦除:
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),一次擦除一个元素是低效的,因为它会导致重复移动。这里首选的习惯用法是"remove/erase",但如果您不想直接按元素值删除,则需要提供合适的谓词。为简洁起见,下面是一个使用lambdas的示例:
std::vector<int> v;
v.erase(std::remove_if(v.begin(), v.end(),
[](int n)->bool{return some_criterion(n);}),
v.end());
在你的情况下,你可以把写成[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());
问题在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() );
它叫做:
- <
- Erase-Remove成语/gh>
- 从C++本机插件更新Vector3数组
- 删除一个线程上有数百万个字符串的大型哈希映射会影响另一个线程的性能
- QGraphicsPolygonItem在拖动时未更新QPolygonF坐标
- C++映射:具有自定义类的运算符[]不起作用(总是返回0)
- 将函数类成员映射到类本身内部
- 如何在 C# 中映射双 C 结构指针?
- 为什么 c++ 映射值不针对同一键更新?
- C++ STL 映射同时更新所有值
- 两个进程之间的共享映射内存在编辑时未更新
- 如何使用密钥 2 更新 STL 映射键 1 并将值复制到键 2 中
- 将项目"更新插入"到映射<键、shared_ptr的正确方法<foo>>
- 如何更新映射C++中元素的值
- 通过引用将 std::map 传递给不更新映射的类的构造函数
- 更新标准::映射对象数据
- 在C++11中的每个循环迭代之后更新映射
- 在c++中更新映射值
- 通过删除一些键和一些元素来更新映射的问题
- 如何更新map
>类型的映射 - 如何在C++中更新映射的对象
- 检查映射中是否存在关键字,然后更新值