提问人:coin cheung 提问时间:12/26/2019 最后编辑:Evgcoin cheung 更新时间:12/28/2019 访问量:576
如何获取两个 std::map 的公钥?
How could I obtain the common keys of two std::map?
问:
假设有两个 c++:std::map
std::map<string, int> m1{{"n1", 1}, {"n2", 2}, {"n3", 3}};
std::map<string, int> m2{{"n2", 3}, {"n4", 2}, {"n1", 9}};
我想获取包含两个映射的公共键。std::set
std::set<string> common = ...;
我希望我能优雅地做到这一点,所以我最好避免使用循环,如果我可以在命名空间中找到一些方法,或者从中找到一些方法会更好,我该怎么做?std
<algorithm>
答:
1赞
parktomatomi
12/26/2019
#1
要查找公共密钥,您需要过滤其密钥不在中的项目,然后提取密钥。可悲的是,中没有或任何类型的组合过滤器/映射操作,所以如果你使用纯算法,这是一个两步操作:m1
m2
transform_if
<algorithm>
std::map<string, int> common_m;
std::copy_if(
m1.begin(), m1.end(),
std::inserter(common_m, common_m.end()),
[&m2](auto&& kv) { return m2.find(kv.first) != m2.end(); });
std::set<string> common_keys;
std::transform(
common_m.begin(), common_m.end(),
std::inserter(common_keys, common_keys.end()),
[](auto&& kv) { return kv.first; });
演示 - https://godbolt.org/z/6982Pm
编写步骤很笨拙,因为没有惰性操作,每个操作都必须在新容器中具体化。<algorithm>
这就是 ranges-v3 库的功能,该库已作为 Ranges TS 并入 C++20 标准。它允许 ML 风格的惰性操作,这些操作可以组合成一个单行:
std::set<string> common_keys = m1
| views::remove_if([&m2](auto&& kv) { return m2.find(kv.first) == m2.end(); })
| views::transform([](auto&& kv) { return kv.first; })
| to<std::set>;
演示 - https://godbolt.org/z/CKUFFz
3赞
Evg
12/26/2019
#2
使用 std
::set_intersection 的可能解决方案:
template<class It>
class Key_iterator {
public:
Key_iterator(It it) : it_(it) {}
Key_iterator& operator++() {
++it_;
return *this;
}
bool operator==(const Key_iterator& other) const {
return it_ == other.it_;
}
bool operator!=(const Key_iterator& other) const {
return it_ != other.it_;
}
auto operator*() const {
return it_->first;
}
private:
It it_;
};
std::map<std::string, int> m1{{"n1", 1}, {"n2", 2}, {"n3", 3}};
std::map<std::string, int> m2{{"n2", 3}, {"n4", 2}, {"n1", 9}};
std::vector<std::string> s;
std::set_intersection(Key_iterator(m1.begin()), Key_iterator(m1.end()),
Key_iterator(m2.begin()), Key_iterator(m2.end()), std::back_inserter(s));
// s = {"n1", "n2"}
std::set_intersection
需要对两个范围进行排序,并按排序顺序保留其键。所以它们很合身。std::map
如果 Boost 可用,则无需编写适配器代码。使用 boost
::transform_iterator 可以将此代码简化为:Key_iterator
std::map<std::string, int> m1{{"n1", 1}, {"n2", 2}, {"n3", 3}};
std::map<std::string, int> m2{{"n2", 3}, {"n4", 2}, {"n1", 9}};
auto key_iterator = [](auto it) {
return boost::transform_iterator(it, [](auto& p) { return p.first; });
};
std::vector<std::string> s;
std::set_intersection(key_iterator(m1.begin()), key_iterator(m1.end()),
key_iterator(m2.begin()), key_iterator(m2.end()), std::back_inserter(s));
评论
0赞
Narase
4/13/2021
真的很喜欢这个Key_iterator解决方案。现在做了很多 map-alg,这很有帮助
评论
std::transform
std::erase_if