问题描述
首先,我有以下两个对象,都充满了数据:
std::vector<std::map<std::uint8_t,std::uint8_t>> x1;
std::vector<std::map<std::uint8_t,std::uint8_t>> x2;
我的目标是在x2
内部(通过 key 键)进行搜索,检查x1
中是否不存在x2
中的任何值,然后从x1
中删除它。
我尝试使用以下代码段,但无济于事(无法编译!):
for (auto i = x1.begin(); i != x1.end(); ++i)
{
auto it = std::find(x2.begin(),x2.end(),i);
if (it == x2.end())
{
x1.erase(i);
}
}
我在做什么错?您能否分享一些有关如何解决此问题的见解?
解决方法
您的代码有几个问题:
-
std::find()
搜索单个匹配元素,在这种情况下,这意味着您必须给它一个std::map
进行搜索。但是您传递的是i
迭代器本身,而不是它所引用的std::map
。您需要取消引用i
,例如:auto it = std::find(x2.cbegin(),x2.cend(),*i);
-
在调用
x1.erase(i)
时,i
变得无效,这意味着循环无法再使用i
-不能用于++i
,不能用于i != x1.end()
。您需要保存erase()
返回的新迭代器,该迭代器指的是被擦除后的 next 元素。这意味着您还需要将循环逻辑更新为在调用i
时不递增erase()
,例如:for (auto i = x1.cbegin(); i != x1.cend(); ) { auto it = std::find(x2.cbegin(),*i); if (it == x2.cend()) i = x1.erase(i); else ++i; }
-
最后,当使用
std::find()
时,您正在将整个std::map
对象进行比较。如果您只想比较键,请尝试以下类似操作:for (auto i = x1.cbegin(); i != x1.cend(); ) { const auto &m1 = *i: auto it = std::find_if(m1.cbegin(),m1.cend(),[&](const decltype(m1)::value_type &m1_pair) { // or (const auto &m1_pair) in C++14... return std::find_if(x2.cbegin(),[&](const decltype(x2)::value_type &m2){ // or (const auto &m2) in C++14... return m2.find(m1_pair.first) != m2.cend(); } ); } ); if (it == m1.cend()) i = x1.erase(i); else ++i; }
您还可以使用一些功能:Playground
#include <algorithm>
#include <functional>
// removes maps from x1,that are equal to none of x2 maps
auto remove_start = std::remove_if(x1.begin(),x1.end(),[&](const auto& x1_map){
return std::none_of(x2.begin(),x2.end(),std::bind(std::equal_to(),x1_map,std::placeholders::_1));
});
x1.erase(remove_start,x1.end());
编辑:仅检查密钥,请将std :: equal_to更改为自定义lambda
auto keys_equal = [](auto& m1,auto& m2){
return m1.size() == m2.size()
&& std::equal(m1.begin(),m1.end(),m2.begin(),[](auto& kv1,auto& kv2){ return kv1.first == kv2.first; });
};
// removes maps from x1,that are equal to none of x2 maps
auto remove_start =
std::remove_if(x1.begin(),[&](const auto& x1_map){
return std::none_of(x2.begin(),std::bind(keys_equal,std::placeholders::_1));
});
x1.erase(remove_start,x1.end());