-1

I have a stacked map that looks like this: std::multimap <double, std::map<int,TypeA> > m

How can I point to the value of TypeA? I have tried:

TypeA t = m.second.second

or pointer:

for (std::multimap <double, std::map<int,StopID>>::iterator p = m.begin(); p != m.end(); p ++ ){
....
   TypeA t = p->second->second
}

However, I got this error

no member named second in std::map...

Any idea?

Ha An Tran
  • 337
  • 1
  • 21

2 Answers2

2
for (std::multimap <double, std::map<int,StopID>>::iterator p = m.begin(); p != m.end(); p ++ ){

In the above you are iterating over the multimap and p->second points at the whole inner map, not a single entry in it. You need to iterate over the map too to access all entries in that.

You can use range based for-loops and structured bindings to make life easier.

for(auto& [the_double, the_map] : m) {
    for(auto& [the_int, the_type_a] : the_map) {
        // do what you want with the TypeA reference "the_type_a"
    }
}

Edit: If I understand comments correctly, the map always contains exactly one int, TypeA pair - and in that case, just replace the map with a std::pair<int, TypeA> and you can have one loop only:

#include <utility> // std::pair

int main() {
    std::multimap <double, std::pair<int, TypeA>> m;

    for(auto& [the_double, the_pair] : m) {
        auto& [the_int, the_type_a] = the_pair;
        // do what you want with the int and TypeA references
    }
}
Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108
  • what is the time complexity of 2 for loops above? – Ha An Tran Mar 08 '20 at 12:51
  • 2
    @HaAnTran Exactly the same as in the accepted answer that also uses the same two loops. Why have a map that always has exactly one element? It sounds like a `std::pair` would be better. I added an example for that. – Ted Lyngmo Mar 08 '20 at 13:33
  • Is it possible to have a condition that the "int element" in std::pair is sorted in ascending order? That's why I chose map instead of pair, but the insertion is quite tricky. For example: My multimap can look like this:```{10, 3, TypeA a1},{10, 7, TypeA a2},{15, 7, TypeA a3}``` – Ha An Tran Mar 08 '20 at 14:00
  • 1
    @HaAnTran I'm not sure I understand. A `map` with one element is sorted in both ascending and decending order. A single `std::pair` too. There is nothing to sort so to speak. – Ted Lyngmo Mar 08 '20 at 14:29
  • 1
    [Example](https://godbolt.org/z/NHh4C7) - As you can see, the sorting is done on the `multimap` key and since the `map` only has one element, what is there to sort? – Ted Lyngmo Mar 08 '20 at 14:37
  • for my case, if the_double values are equal, I will continue to consider which map has smaller the_int to come first. However, from this example https://godbolt.org/, both std::map and std::pair doesn't consider the condition (the output should be ```{1.1 2}, {3.3 1}, {3.3 2}``` – Ha An Tran Mar 08 '20 at 14:42
  • 1
    @HaAnTran There was no example @ godbolt - but how does using a `map` instead of a `pair` solve the ordering in the multimap? It doesn't. You'll have to insert the elements with equal keys in the order your want them. Perhaps you shouldn't use a `multimap` either. If you use a plain `vector` and put a `struct { double d; int i; TypeA ta; };` in it, sorting will be easy. – Ted Lyngmo Mar 08 '20 at 14:50
  • Thanks, will try that out! – Ha An Tran Mar 08 '20 at 14:51
  • You could even use a `multiset` or `set` for it. – Ted Lyngmo Mar 08 '20 at 14:52
  • What is the difference between ```multiset``` and ```multimap```. For my case I have 3 variables to store (the_double, the_int and the_TypeA). The sorting is done first on the_double, then the_int (if 2 the_doubles are equal). – Ha An Tran Mar 08 '20 at 14:55
  • 1
    @HaAnTran In a `*set`, all members can take part in the sorting. There's no mapping from key to value. You have just a set of entities and decide how you want them sorted yourself. [Example](https://godbolt.org/z/J4_-Xb) – Ted Lyngmo Mar 08 '20 at 15:46
  • for 3 elements, should the structure be ```std::multiset> ``` – Ha An Tran Mar 08 '20 at 16:01
  • You can decide the ordering just as you wish. I chose to put `operator<` in the class, but if you want it outside, you can create the `multiset` with a compare object. – Ted Lyngmo Mar 08 '20 at 16:39
1

m->second is a std::map object. You must use a loop for the next map:

using multimap_t = std::multimap <double, std::map<int, TypeA>>;
for (multimap_t::iterator p = m.begin(); p != m.end(); p++) {
    std::map<int, TypeA>>& map = p->second;
    for (decltype(p->second)::iterator miter = map.begin(); miter != map.end(); ++miter) {
        TypeA t = miter->second;
        // ...
    }
}

A simpler version with auto (C++11):

for (auto p = m.begin(); p != m.end(); p++) {
    auto& map = p->second;
    for (auto miter = map.begin(); miter != map.end(); ++miter) {
        TypeA t = miter->second;
        // ...
    }
}
Dessus
  • 301
  • 2
  • 10