如何使用 C++11 中的函数式编程从映射中获取密钥
How to use functional programming in C++11 to obtain the keys from a map?
在数学观点中,std::map<K,V> m
是一个函数f m,其中所有域和范围元素(x,y)对∈K × V,使得fm(x)= y。
所以,我想得到 fm 的域,即所有键的集合(或者可能是范围 - 所有值的集合)。我可以用 C++11 按程序执行此操作,如下所示:
std::unordered_set<K> keys;
for (const auto& kv_pair : m) { keys.insert(kv_pair->first); }
右?但是 - 我想在功能上做到这一点(阅读:以一种让我觉得优越的花哨方式)。我该怎么做?
笔记:
- 我不一定需要结果是 std::unordered_set;可以替换这样一组的东西也可能起作用(例如,设置立面)。
- 可读性、(合理)简洁和避免无端复制数据都是考虑因素。
Boost.Range
恰恰提供了这一点,适配器map_keys
.查看文档中的此示例。
你可以写:
auto keys = m | boost::adaptors::map_keys;
// keys is a range view to the keys in your map, no copy involved
// you can use keys.begin() and keys.end() to iterate over it
编辑:我将在下面留下我的旧答案,它使用迭代器而不是范围。请注意由两个boost::transform_iterator
表示的范围仍表示地图中的键集。
IMO 执行此操作的功能方式需要一个指向映射键的迭代器,以便您可以简单地使用 std::copy
.这是有道理的,因为你没有转换或积累任何东西,你只是在复制密钥。
不幸的是,该标准不提供迭代器适配器,但您可以使用 Boost.Iterator
提供的适配器。
#include <algorithm>
#include <map>
#include <unordered_set>
#include <boost/iterator/transform_iterator.hpp>
struct get_first
{
template<class A, class B>
const A & operator()(const std::pair<A,B> & val) const
{
return val.first;
}
};
int main()
{
std::map<int, std::string> m;
std::unordered_set<int> r;
// ...
std::copy(boost::make_transform_iterator(m.begin(), get_first{}),
boost::make_transform_iterator(m.end(), get_first{}),
std::inserter(r, r.end()) );
}
让一个迭代器取消引用元组/对的 Kth
元素会更有表现力,但transform_iterator
可以很好地完成这项工作。
我直言,直观函数式代码的一个重要特征是算法实际上返回结果,而不是在其他地方设置一些变量作为副作用。 这可以通过std::accumulate
来完成,例如:
#include <iostream>
#include <set>
#include <map>
#include <algorithm>
int main()
{
typedef std::map<int, int> M;
M m { {1, -1}, {2, -2}, {3, -3}, {4, -4} };
auto&& x = std::accumulate(std::begin(m), std::end(m), std::set<int>{},
[](std::set<int>& s, const M::value_type& e)
{
return s.insert(e.first), std::move(s);
// .first is key,
}); // .second is value
for (auto& i : x)
std::cout << i << ' ';
std::cout << 'n';
}
输出:
1 2 3 4
看它在这里运行
std::begin(m), std::end(m)
位实际上是一个令人头疼的问题,因为它阻碍了此类操作的链接。 例如,如果我们可以将"功能"操作(如上面的"GET KEYS")与其他操作链接在一起,那将是理想的......
x = m. GET KEYS . SQUARE THEM ALL . REMOVE THE ODD ONES
。或者至少...
x = f(f(f(m, GET KEYS), SQUARE THEM ALL), REMOVE THE ODD ONES)
。但是你必须自己编写一些琐碎的代码才能到达那里,或者选择一个支持函数式"风格"的库。
有很多方法可以写这个。一种稍微"实用"的方式是:
vector<string> keys;
transform(begin(m), end(m), back_inserter(keys), [](const auto& p){ return p.first; });
但是为了真正改进这一点并使用标准库实现更实用的风格,我们需要像 Eric Niebler 的 Range Proposal 这样的东西来标准化。与此同时,有许多基于范围的非标准库,如 Eric 的 range-v3 和 boost Range,您可以使用它们来获得更实用的样式。
std::map<int, int> m;
std::unordered_set<int> keys;
std::for_each(m.begin(), m.end(), [&keys](decltype(*m.begin()) kv)-> void {keys.insert(kv.first);});
- 我如何获取从 C++ 到 C 的映射<字符串、int>#
- C++映射有2个键,这样任何1个键都可以用来获取值
- 与多个 for 循环与单个 for 循环 wrt 相关的性能从多映射获取数据
- 当映射包含字符串向量作为值时,从值中获取键的有效方法
- C++ 在集合和映射容器中获取唯一值
- 通过从矢量中获取键和与映射中的键对应的值来创建映射
- 虚幻引擎 - 如何通过C++代码获取轴映射
- 为C++中的无序映射获取给定输入键的错误值
- 我尝试使用MAP容器来映射资源,现在RESOURCEFILE正在获取所有信息.为什么
- 在boost::hana中给定一个键元组,如何从映射中获取值元组
- 如何获取二叉树(集合或映射)的根
- 将从std::映射中获取的std::pair引用传递给接受std::对引用的函数
- 获取指向映射内结构的指针
- STL映射比较器能否以某种方式获取指向映射本身的指针?
- 如何从映射中获取值并在 C++ 的 switch 语句中使用它
- 编译按映射类型获取元素的映射错误元组
- C++ 当第二个元素为 X 时,映射获取第一个元素
- C++11:std::unordered_map<int,std::stack<int>> 从映射获取值而无需多次复制
- 在 STL 中使用映射获取编译错误C++
- 无法从指向多态类的指针映射获取有效的指针