【问题标题】:Setting all values in a std::map在 std::map 中设置所有值
【发布时间】:2008-09-26 12:57:40
【问题描述】:

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

【问题讨论】:

  • Torsten,C++ STL map没有实现为哈希表。

标签: c++ stl


【解决方案1】:

使用循环迄今为止最简单的方法。其实就是单行:[C++17]

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

不幸的是,C++ 算法对关联容器的支持在 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);

【讨论】:

    【解决方案2】:

    我遇到了同样的问题,但发现 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);
    

    【讨论】:

      【解决方案3】:

      boost::assign 库有各种简洁的东西来帮助初始化容器的内容。我认为这可以用来避免显式地遍历地图。不幸的是,地图是难以初始化的奇怪野兽,因为键必须是唯一的。底线是简单的 for 循环可能是初始化地图的最佳方式。它可能不是超级优雅,但它可以完成工作,并且任何熟悉 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。
      像这样的东西应该适用于多图(未经测试的代码 sn-p)

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

      正如 Konrad Rudolph 所指出的,您不能使用相同的确切值初始化地图,因为键必须是唯一的。

      这让生活变得更加复杂(有趣吗?)。可能是这样的:

      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("")));
      

      【讨论】:

      • 您的代码 sn-p 无法在简单的地图中工作,因为您再次插入相同的键。在这种情况下,您必须使用生成器函数。
      • 好点!它必须是多图,或者使用 repeat_fun 我想知道最初的问题想要什么?
      • 是的 Boost::assign 是您最简单的地图填充解决方案。完全同意,除了语法是圆滑的几乎像脚本一样。
      猜你喜欢
      • 1970-01-01
      • 2012-12-13
      • 1970-01-01
      • 2021-12-23
      • 2017-07-15
      • 1970-01-01
      • 1970-01-01
      • 2015-03-13
      相关资源
      最近更新 更多