9

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?

ekad
  • 14,436
  • 26
  • 44
  • 46
jabk
  • 1,388
  • 4
  • 25
  • 43
  • What does "all MyObjects are stored in a std::vector" mean? You also said the `dataMap` keys were `*MyObject` 0 u.e. just a pointer to MyObject... and a potential memory leak, right? – doctorlove Oct 23 '14 at 12:10
  • It means that when i'm filling the map it's reading from vector where the key is `MyObject.name` and value is the object itself. I used a pointer to avoid copying the object – jabk Oct 23 '14 at 12:18
  • 1
    Maybe look at [std::multimap::equal_range](http://www.cplusplus.com/reference/map/multimap/equal_range/). – Galik Oct 23 '14 at 12:20
  • Be very careful with that - make sure the vector never changes while you point at its contents - vectors can move things if you push_back – doctorlove Oct 23 '14 at 12:21
  • @doctorlove The function that returns the vector is `const`, do I also need to stress that in multimap declaration? – jabk Oct 23 '14 at 12:23
  • In addition to what Galik linked, you might want to use `std::multimap::count` to get the number of values with the key. Also, as long as no one modifies the `vector` during the lifetime of `dataMap` or it's possible copies, you'll be fine. – eerorika Oct 23 '14 at 12:26
  • 5
    If you know the keys it's simple see equal_range, If not there are other questions - http://stackoverflow.com/questions/247818/stlmultimap-how-do-i-get-groups-of-data, http://stackoverflow.com/questions/11554932/how-can-i-get-all-the-unique-keys-in-a-multimap, http://stackoverflow.com/questions/9371236/is-there-an-iterator-across-unique-keys-in-a-stdmultimap – doctorlove Oct 23 '14 at 12:29
  • Strayed off topic - but what are you really trying to do? Count_if? http://en.cppreference.com/w/cpp/algorithm/count – doctorlove Oct 23 '14 at 12:37
  • @doctorlove kind of, but i need just one number that indicates how many same keys there are for a certain group – jabk Oct 23 '14 at 12:42

1 Answers1

7

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.

Galik
  • 47,303
  • 4
  • 80
  • 117
  • That helped clear up some things, thanks :) – jabk Oct 23 '14 at 13:40
  • @user2202368 I didn't notice you had posted a solution in the question. The only real different I can see is that my version uses the returned `equal_range()` to select the next iterator in the outer for-loop which is probably slightly more efficient than calculating `upper_bound()` again. – Galik Oct 23 '14 at 14:11