stl::multimap - how do i get groups of data?

為{幸葍}努か 提交于 2019-11-26 04:41:13

问题


Multimap essentially has groups of data sorted by the key. I want a method by which I could access these individual groups and get their aggregate values. For example, in a std::multimap< string, int > I store

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

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

Having stored these values, I should be able to iterate this multimap and get the aggregate values of each \"group\". Problem is there aren\'t any functions defined in STL to access MultiMaps in such a way. I could use lower_bound, upper_bound to manually iterate the multimap and total the group\'s contents, but I am hoping there could be better ways already defined in STL ? Can anyone propose a solution as to how I could get the aggregate values for a group in the above example.


回答1:


pair<Iter, Iter> range = my_multimap.equal_range("Group1");
int total = accumulate(range.first, range.second, 0);

Is one way.

Edit:

If you don't know the group you are looking for, and are just going through each group, getting the next group's range can be done like so:

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



回答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:


If you already know the keys, you can use multimap::equal_range to get the iterators to the beginning and end of the group; use any standard algorithm to get the desired results from the range. If you don't know the keys, you can start at begin() and iterate through them yourself, comparing keys to find the start of each new group.




回答4:


You can use an alternate container that can contain the aggregate sums of each group. To do this you might do something like:

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

Of course, if you have Lambda's (in C++0x) it could be simpler:

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

Syntax:

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

The function equal_range() returns two iterators - one to the first element that contains key, another to a point just after the last element that contains key.




回答6:


Not a multimap answer, but you can do things like the following if you so choose.

#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";
        }
    }
}


来源:https://stackoverflow.com/questions/247818/stlmultimap-how-do-i-get-groups-of-data

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!