【问题标题】:stl::multimap - how do i get groups of data?stl::multimap - 我如何获取数据组?
【发布时间】:2008-10-29 18:11:42
【问题描述】:

Multimap 本质上具有按键排序的数据组。我想要一种方法,通过它我可以访问这些单独的组并获取它们的汇总值。 例如,在 std::multimap< string, int > 我存储

{"Group1", 1}, 
{"Group1", 2}, 
{"Group1", 3}, 

{"Group2", 10}, 
{"Group2", 11}, 
{"Group2", 12}

存储了这些值后,我应该能够迭代这个多图并获得每个“组”的聚合值。问题是在 STL 中没有定义任何函数来以这种方式访问​​ MultiMaps。我可以使用lower_boundupper_bound 手动迭代多图并汇总组的内容,但我希望在 STL 中已经定义了更好的方法?任何人都可以提出一个解决方案,说明我如何在上面的示例中获取组的聚合值。

【问题讨论】:

标签: c++ stl multimap


【解决方案1】:
pair<Iter, Iter> range = my_multimap.equal_range("Group1");
int total = accumulate(range.first, range.second, 0);

是一种方式。

编辑:

如果您不知道要查找的组,并且只是遍历每个组,则可以像这样获取下一个组的范围:

template <typename Pair>
struct Less : public std::binary_function<Pair, Pair, bool>
{
    bool operator()(const Pair &x, const Pair &y) const
    {
        return x.first < y.first;
    }
};

Iter first = mmap.begin();
Iter last = adjacent_find(first, mmap.end(), Less<MultimapType::value_type>());

【讨论】:

  • 不应该是x.first == y.first;吗?你为什么用operator&lt;?根据adjacent_finddocument,谓词参数应该返回比较结果,true(非零)表示它们被视为相等,false(零)表示不相等。为什么不相等的结果返回 true?
  • 是的,这似乎是一个错误。 adjacent_find 需要一个“相等”的谓词。另外,我确定有 std::equal_to&lt;T&gt; 可以使用。
  • @leemes 我相信您的编辑会将行为更改为不正确的行为。 “小于”运算符应该在更改键之前找到最后一个元素(可能是 advanced 到具有新键的第一个元素),而使用相等运算符它只会将迭代器返回到相同的元素(@987654330 @) 元素
  • 我已将上次编辑回滚到原始@Greg 的版本
【解决方案2】:
// samekey.cpp -- Process groups with identical keys in a multimap

#include <iostream>
#include <string>
#include <map>
using namespace std;

typedef multimap<string, int> StringToIntMap;
typedef StringToIntMap::iterator mapIter;

int main ()
{
    StringToIntMap mymap;

    mymap.insert(make_pair("Group2", 11));
    mymap.insert(make_pair("Group1",  3));
    mymap.insert(make_pair("Group2", 10));
    mymap.insert(make_pair("Group1",  1));
    mymap.insert(make_pair("Group2", 12));
    mymap.insert(make_pair("Group1",  2));

    cout << "mymap contains:" << endl;

    mapIter m_it, s_it;

    for (m_it = mymap.begin();  m_it != mymap.end();  m_it = s_it)
    {
        string theKey = (*m_it).first;

        cout << endl;
        cout << "  key = '" << theKey << "'" << endl;

        pair<mapIter, mapIter> keyRange = mymap.equal_range(theKey);

        // Iterate over all map elements with key == theKey

        for (s_it = keyRange.first;  s_it != keyRange.second;  ++s_it)
        {
           cout << "    value = " << (*s_it).second << endl;
        }
    }

    return 0;

}   //  end main

// end samekey.cpp

【讨论】:

    【解决方案3】:

    如果你已经知道key,你可以使用multimap::equal_range来获取到组首尾的迭代器;使用任何标准算法从范围中获得所需的结果。如果您不知道密钥,可以从begin() 开始并自己遍历它们,比较密钥以找到每个新组的开始。

    【讨论】:

      【解决方案4】:

      您可以使用可包含每个组的总和的备用容器。为此,您可能会执行以下操作:

      template <class KeyType, class ValueType>
      struct group_add {
        typedef map<KeyType, ValueType> map_type;
        map_type & aggregates;
        explicit group_add(map_type & aggregates_)
          : aggregates(aggregates_) { };
        void operator() (map_type::value_type const & element) {
          aggregates[element.first] += element.second;
        };
      };
      
      template <class KeyType, class ValueType>
      group_add<KeyType, ValueType>
      make_group_adder(map<KeyType, ValueType> & map_) {
        return group_add<KeyType, ValueType>(map_);
      };
      
      // ...
      multimap<string, int> members;
      // populate members
      map<string, int> group_aggregates;
      for_each(members.begin(), members.end(),
        make_group_adder(group_aggregates));
      // group_aggregates now has the sums per group
      

      当然,如果你有 Lambda(在 C++0x 中),它可能会更简单:

      multimap<string, int> members;
      map<string, int> group_aggregates;
      for_each(members.begin(), members.end(),
        [&group_aggregates](multimap<string, int>::value_type const & element) {
          group_aggregates[element.first] += element.second;
        }
        );
      

      【讨论】:

        【解决方案5】:
        equal_range
        

        语法:

        #include <map>
        pair<iterator, iterator> equal_range( const key_type& key );
        

        函数equal_range() 返回两个迭代器——一个指向包含键的第一个元素,另一个指向包含键的最后一个元素之后的点。

        【讨论】:

          【解决方案6】:

          不是多地图答案,但如果您愿意,您可以执行以下操作。

          #include <iostream>
          #include <vector>
          #include <map>
          #include <string>
          #include <boost/assign/list_of.hpp>
          #include <boost/foreach.hpp>
          using namespace std;
          using namespace boost;
          using namespace boost::assign;
          
          int main() {
              typedef map<string, vector<int> > collection;
              collection m;
              m["Group 1"] = list_of(1)(2)(3);
              m["Group 2"] = list_of(10)(11)(12);
              collection::iterator g2 = m.find("Group 2");
              if (g2 != m.end()) {
                  BOOST_FOREACH(int& i, g2->second) {
                      cout << i << "\n";
                  }
              }
          }
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多