如何从集合初始化地图

时间:2016-10-01 00:41:18

标签: c++ stdmap stdset

我想使用std::map(或std::set)的元素设置std::vector的键。

以下内容......

std::set<int> keys = { 3,4,6 };
std::map<int,string> results(keys); // syntax error

这可以在没有明确迭代集合的情况下完成吗?

2 个答案:

答案 0 :(得分:2)

你做不到。 map不是set。即使底层结构相似,它们也是根本不同的容器。

那说,一切皆有可能。如果范围的元素已经排序,则std::map的范围构造函数是线性时间,set为我们保证。因此,您需要做的就是将变换器应用于每个元素以生成新范围。最简单的方法是使用boost::make_transform_iterator之类的东西(或自己动手):

template <class K, class F
    class V = decltype(std::declval<F&>()(std::declval<K const&>()))::second_type>
std::map<K, V> as_map(std::set<K> const& s, F&& f) {
    return std::map<K,V>(
        boost::make_transform_iterator(s.begin(), f),
        boost::make_transform_iterator(s.end(), f));
}

std::map<int,string> results =
    as_map(keys, [](int i){
        return std::make_pair(i, std::string{});
    });

如果你总是想要默认初始化,可以简化为:

template <class V, class K>
std::map<K, V> as_map_default(std::set<K> const& s) {
    auto f = [](K const& k) { return std::make_pair(k, V{}); }
    return std::map<K,V>(
        boost::make_transform_iterator(s.begin(), f),
        boost::make_transform_iterator(s.end(), f)); 
}

std::map<int,string> results = as_map_default<string>(keys);

答案 1 :(得分:1)

  

这可以在没有明确迭代集合的情况下完成吗?

没有。没有迭代它就无法知道集合中的密钥。您可以编写函数使其显示,就好像存在隐式转换一样,但这些函数必须最终迭代源集合。

一种简单的方法如下:

#include <set>
#include <map>
#include <string>

auto build_map(const std::set<int>& source) -> std::map<int,std::string>
{
  std::map<int,std::string> results;
  for (auto const& i : source) {
    results[i];
  }
  return results;
}

int main()
{
  std::set<int> keys = { 3,4,6 };
  auto results = build_map(keys);
}

当然,如果能提高可读性,我们可能会进行调整:

#include <set>
#include <vector>
#include <unordered_set>
#include <map>
#include <string>
#include <utility>

template<class MappedType, class SourceContainer>
auto build_map(SourceContainer&& source)
{
  using source_type = std::decay_t<SourceContainer>;
  using key_type = typename source_type::value_type;

  std::map<key_type , MappedType> results;
  for (auto const& i : source) {
    results[i];
  }
  return results;
}

int main()
{
  std::set<int> keys = { 3,4,6 };
  auto results = build_map<std::string>(keys);

  // also
  results = build_map<std::string>(std::vector<int>{3, 4, 6});
  results = build_map<std::string>(std::unordered_set<int>{3, 4, 6});
}