How to iterate through a multimap and print values grouped by key?

jabk picture jabk · Oct 23, 2014 · Viewed 15.9k times · Source

I have std::multimap<string, MyObject*> dataMap; where the keys are MyObject.name and all MyObjects are stored in a std::vector<MyObject>.

After filling the map I need to print the contents of dataMap grouped by the same key, where I first need number of same keys with the help of dataMap.count(MyObject.name) and then all the values with this key.

I was thinking of using two for loops where the first loop iterates through "key group names" and counts all the keys that belong in this group, and the other for loop iterates through all the keys in certain group and prints the MyObject.information

for(//iterate through group key names){
   //print number of key occurences
   for(//iterate through a certain group{
      //print MyObject.information for all the keys in a group
   }

}

The problem is, i don't really know how would implement this or rather how would I use iterators to my will. Any ideas?

EDIT: From the provided links i created this

 for(std::multimap<string, MyObject*>::const_iterator itUnq = dataMap.cbegin();
     itUnq != dataMap.cend(); itUnq = dataMap.upper_bound(itUnq->first)){

        std::cout << dataMap.count(itUnq->second->name)
                  << std::endl;

        std::pair <std::multimap<string, MyObject*>::const_iterator, 
                   std::multimap<string, MyObject*>::const_iterator> groupRange;
        groupRange = dataMap.equal_range(itUnq->second->code);

        //iterate through keys inside the group
        for(std::multimap<string, MyObject*>::const_iterator itGroup = groupRange.first;
            itGroup != groupRange.second; ++itGroup){

            std::cout << itGroup->second->information

        }

Comments?

Answer

Galik picture Galik · Oct 23, 2014

From what I understand of your problem you can implement it using std::multimap::equal_range.

Something a bit like this:

#include <map>
#include <ctime>
#include <string>
#include <vector>
#include <iostream>
#include <algorithm>

struct MyObject
{
    std::string name;
    int information;

    MyObject(const std::string& name, int information)
    : name(name), information(information) {}
};

int main()
{
    std::srand(std::time(0));

    std::vector<MyObject> dataVec;
    std::multimap<std::string, MyObject*> dataMap;

    // Give each object a random letter
    // between A-J as a name and some data
    for(auto i = 0; i < 10; ++i)
        dataVec.emplace_back(std::string(1, 'A' + std::rand() % 10), i);

    // Fill dataMap from dataVec
    for(auto&& data: dataVec)
        dataMap.emplace(data.name, &data);

    // Select the correct type for calling the equal_range function
    decltype(dataMap.equal_range("")) range;

    // iterate through multimap's elements (by key)
    for(auto i = dataMap.begin(); i != dataMap.end(); i = range.second)
    {
        // Get the range of the current key
        range = dataMap.equal_range(i->first);

        // Now print out that whole range
        for(auto d = range.first; d != range.second; ++d)
            std::cout << d->first << ": " << d->second->information << '\n';
    }
}

Run It Here

If that's not precisely what you want, maybe it will still give you ideas how to solve your specific problem.