在std::map中设置所有值

9
如何在不使用循环迭代每个值的情况下将std::map中的所有值设置为相同的值?

Torsten,C++ STL的map并不是以哈希表实现的。 - Konrad Rudolph
3个回答

18

使用循环是最简单的方法。实际上,这只需要一行代码:[C++17]

for (auto& [_, v] : mymap) v = value;

很遗憾,在C++20之前,关联容器的算法支持并不是很完善。因此,我们不能直接使用 std::fill

然而,为了在C++20之前使用它们,我们需要编写适配器,例如对于std::fill,需要一个迭代器适配器。下面是一个最小化可行但不太规范的实现,用于说明需要多大的努力。我不建议直接使用它。请使用库(例如Boost.Iterator)进行更通用、生产级别的实现。

template <typename M>
struct value_iter : std::iterator<std::bidirectional_iterator_tag, typename M::mapped_type> {
    using base_type = std::iterator<std::bidirectional_iterator_tag, typename M::mapped_type>;
    using underlying = typename M::iterator;
    using typename base_type::value_type;
    using typename base_type::reference;

    value_iter(underlying i) : i(i) {}

    value_iter& operator++() {
        ++i;
        return *this;
    }

    value_iter operator++(int) {
        auto copy = *this;
        i++;
        return copy;
    }

    reference operator*() { return i->second; }

    bool operator ==(value_iter other) const { return i == other.i; }
    bool operator !=(value_iter other) const { return i != other.i; }

private:
    underlying i;
};

template <typename M>
auto value_begin(M& map) { return value_iter<M>(map.begin()); }

template <typename M>
auto value_end(M& map) { return value_iter<M>(map.end()); }

有了这个,我们就可以使用std::fill

std::fill(value_begin(mymap), value_end(mymap), value);

3
我遇到了同样的问题,但发现boost::adaptors::values返回的范围是可变的,因此它可以与常规算法(如std::fill)一起使用。
#include <boost/range/adaptor/map.hpp>
auto my_values = boost::adaptors::values(my_map);
std::fill(my_values.begin(), my_values.end(), 123);

2

boost::assign库有很多有用的东西来帮助初始化容器。我认为这可以用来避免显式地迭代map。不幸的是,map是一种奇怪的动物,因为键必须是唯一的,所以很难初始化。总之,一个简单的for循环可能是初始化map的最佳方式。它可能不是非常优雅,但它能完成任务,并且任何熟悉STL的人都能立即理解它。

map <int,string> myMap;
for( int k=0;k<1000;k++)
  myMap.insert(pair<int,string>(k,string("")));

本文描述了我为得出上述结论所经历的过程。

使用boost::assign可以轻松地将少量值分配给映射。

map<string,int> m; 
insert( m )( "Bar", 1 )( "Foo", 2 );

或者

 map<int,int> next = map_list_of(1,2)(2,3)(3,4)(4,5)(5,6);

在您的情况下,如果您想使用相同的值初始化整个地图,则可以使用repeat和repeat_fun工具。
以下代码片段应该适用于multimap(未经测试)

pair<int,string> init( 0,string(""));
multimap <int,string> myMap = repeat(1000,init);

如Konrad Rudolph所指出的那样,你不能用完全相同的值来初始化一个map,因为键必须是唯一的。这让事情变得更加复杂(有趣?)。也许可以尝试以下代码:
map <int,string> myMap;

struct nextkey
{
   int start;
   nextkey( s ) : start( s ) {}
   pair<int,string> operator () ()
{
   return pair<int,string>(start++,string(""));
}
};

myMap = repeat_fun(1000,nextkey(0));

现在情况变得非常复杂,我认为简单的迭代才是正确的方法。
map <int,string> myMap;
for( int k=0;k<1000;k++)
  myMap.insert(pair<int,string>(k,string("")));

你的代码片段在简单映射中无法工作,因为你一遍又一遍地插入相同的键。在这种情况下,你必须使用生成器函数。 - Konrad Rudolph
好观点!它必须是一个multimap,或者使用repeat_fun。我想知道原始问题想要什么? - ravenspoint
Boost::assign是填充map的最简单解决方案。完全同意,而且语法简洁,几乎像脚本一样。 - Robert Gould

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