用std::vector初始化std::map

5
我想用std::vector对象中包含的键来初始化一个std::map对象。
std::vector<char> mykeys { 'a', 'b', 'c' ];
std::map<char, int> myMap;

如何在不使用循环的情况下完成此操作?

我能否为我的 int 添加默认值?


你能使用一个内部使用循环的标准库函数吗? - juanchopanza
整型数值为0。是的,我可以使用标准库函数,但我在想是否有一种自动构建带有向量的映射的方法? - hao
1
循环有什么问题? - Piotr Skotnicki
1
“没有循环”为什么?只是想知道如何做吗?面试需要吗?还是只是想给老板/自己留下印象? - P0W
4个回答

14

没有一个显式的循环:

std::transform( std::begin(mykeys), std::end(mykeys),
                std::inserter(myMap, myMap.end()),
                [] (char c) {return std::make_pair(c, 0);} );

Demo

如果可能的话,使用基于范围的for循环将更加简洁易读:

for (auto c : mykeys)
    myMap.emplace(c, 0);

4
不行,你不能不使用循环或等价结构实现这个功能。你可以将循环隐藏在一些函数中,例如std::transform(),但无法避免使用循环。此外,编译器经过了良好的训练,可以优化循环(因为它们是无处不在的),因此没有必要避免使用它们。

1
你不能不用循环来完成这个任务。你可以在标准算法下隐藏一个循环,因为你需要将类型为char的对象转换为表示自身的std::pair<const char, int>std::map<char, int>::value_type类型的对象。
例如:
#include <iostream>
#include <vector>
#include <map>
#include <iterator>
#include <algorithm>

int main() 
{
    std::vector<char> v { 'a', 'b', 'c' };
    std::map<char, int> m;

    std::transform( v.begin(), v.end(), std::inserter( m, m.begin() ),
        []( char c ){ return std::pair<const char, int>( c, 0 ); } );

    for ( const auto &p : m )
    {
        std::cout << p.first << '\t' << p.second << std::endl;
    }

    return 0;
}

输出为

a   0
b   0
c   0

1
使用boost库:
template<class Iterators, class Transform>
boost::iterator_range< boost::transform_iterator<
  typename std::decay_t<Transform>::type,
  Iterator
>> make_transform_range( Iterator begin, Iterator end, Transform&& t ) {
  return {
    boost::make_transform_iterator( begin, t ),
    boost::make_transform_iterator( end, t )
  };
}

一个将键映射到对的帮助程序:

template<class T>
struct key_to_element_t {
  T val;
  template<class K>
  std::pair< typename std::decay<K>::type, T > operator()(K&& k) const {
    return std::make_pair( std::forward<K>(k), val );
  }
};
template<class T>
key_to_element_t< typename std::decay<T>::type > key_to_element( T&& t ) {
  return { std::forward<T>(t) };
}

template<class R>
struct range_to_container_t {
  R r;
  template<class C>
  operator C()&& {
    using std::begin; using std::end;
    return { begin(std::forward<R>(r)), end(std::forward<R>(r)) };
  }
};
template<class R>
range_to_container_t<R> range_to_container( R&& r ) { return std::forward<R>(r); }

在所有这些混乱之后,我们得到了:
std::vector<char> mykeys { 'a', 'b', 'c' ];
std::map<char, int> myMap = range_to_container( make_transform_range( begin(mykeys), end(mykeys), key_to_element( 0 ) ) );

该函数直接从mykeys向量中转换序列的元素来构建std::map,有点愚蠢。

相当荒谬。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接