从包含 std::map 个元素的 std::vector 中查找并删除一个值

Finding and erasing a value from a std::vector holding std::map elements

首先,我有以下两个对象,都填充了数据:

std::vector<std::map<std::uint8_t, std::uint8_t>> x1;
std::vector<std::map<std::uint8_t, std::uint8_t>> x2;

我的 objective 是在 x2 中搜索(通过 ),检查 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()returns的新迭代器,它指的是被擦除后的next元素。这意味着您还需要更新循环逻辑以在调用 erase() 时不增加 i,例如:

    for (auto i = x1.cbegin(); i != x1.cend(); )
    {
        auto it = std::find(x2.cbegin(), x2.cend(), *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(), x2.cend(),
                    [&](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(), x1.end(), [&](const auto& x1_map){ 
    return std::none_of(x2.begin(), x2.end(), 
      std::bind(keys_equal, x1_map, std::placeholders::_1)); 
  });
x1.erase(remove_start, x1.end());