如何从存储在std::映射中的std::集中删除元素

How do I delete elements from an std::set that is stored inside a std::map?

本文关键字:std 集中 删除 元素 存储 映射      更新时间:2023-10-16

我在一个类中存储了以下数据结构。

class MyClass {
private:
std::map<std::string, std::set<std::string>> myMap;
public:
void remove(std::string id); //trying to remove items from sets inside myMap
}

然后有一种方法可以尝试从集合中删除项目。我尝试了以下两种方法,但都不起作用。方法1,使用for范围。

for (auto pair : myMap) {
auto set = pair.second;
if (set.count(id)) {
set.erase(id);
}
}

方法2,使用iterator

auto it = myMap.begin();
while (it != myMap.end()) {
auto set = it->second;
if (set.count(id)) {
set.erase(id);
}
it++;
}

在C++中,从映射内的集合中删除元素的正确方法是什么?请注意,当我将myMap定义为std::map<std::string, std::set<std::string>*>(指针(时,我的代码就可以工作了。

假设我们有一个std::map,如下所示:

std::map<std::string, std::set<std::string>> myMap;
myMap["a"].insert("aaa");
myMap["a"].insert("abb");
myMap["a"].insert("acc");
myMap["b"].insert("aaa");
myMap["b"].insert("abb");
myMap["b"].insert("acc");

然后,您可以通过执行以下操作从std::set中删除项目:

for (auto& i : myMap) {
i.second.erase("aaa");
}

演示

为什么从问题出发的方法不起作用

因为,通过执行以下for(auto pair : myMap) {...}auto set = pair.second;,您实际上正在处理来自myMap的数据副本。因此,您需要使用对实际数据的引用,如for(auto& pair : myMap) {...}auto& set = pair.second;

此外,如果数据存在std::set::erase将从std::set中删除数据,因此不需要手动检查是否存在id。

您正在复制要变异的对象。你似乎有Java背景。在C++中,如果您想要引用语义(与值语义相反(,则应该使用引用(在本例中为auto &,而不是auto(。以下是您的操作方法:

#include <algorithm>
#include <map>
#include <set>
#include <string>
class MyClass {
private:
std::map<std::string, std::set<std::string>> myMap;
public:
void remove(std::string const& id) {
std::for_each(myMap.begin(), myMap.end(),
[&id](auto& p) { p.second.erase(id); });
}
};