1
// this has data from elsewhere, just showing its the same type
multimap<string,string> map_with_data;
string string_key = "some_string";

// not working:
multimap<string,string> new_map;

new_map = map_with_data[string_key];

I want a return of a multimap with only the key pairs with the key string_key. What is the right way to do this or is this method of direct copying even possible?

I'm getting: error: no match for ‘operator[]’ (operand types are ‘std::multimap<std::basic_string<char>, std::basic_string<char> >’ and ‘std::string {aka std::basic_string<char>}’)|

Enigma
  • 1,247
  • 3
  • 20
  • 51
  • The nominated duplicate is not asking the same question. You might be able to glean enough from the answers there to answer this one, but that one is about summarizing data in a multimap, where this is about copying part of the contents of the multimap. – Jerry Coffin Mar 17 '15 at 19:54
  • I suppose it's a different question though the goal is the same for me - accessing groups as it were. – Enigma Mar 17 '15 at 19:57
  • If you just want to summarize (or work with) a range from the original map, there's no need to copy the data into a new map to do that. – Jerry Coffin Mar 17 '15 at 19:59
  • Well the goal is to generate a new map with only that subset of data. The original will get thrown away when done while the map with the subset will go elsewhere. I'm using the multimap as a dumping ground and then pulling pieces as I go. – Enigma Mar 17 '15 at 20:01
  • 1
    In that case you could also use `map_with_data.erase(begin(), lower_bound()); map_with_data.erase(upper_bound(), end());` (i.e., keep the same map, but erase the items you don't want). Probably not a huge advantage to that though. – Jerry Coffin Mar 17 '15 at 20:11

1 Answers1

1

Something like the following would be my first choice:

auto r = map_with_data.equal_range(string_key);

multimap<string, string> new_map(r.first, r.second);

This finds all the items in the existing map with the specified key, then initializes the new map from those iterators. If there is no item in the existing map with that key, you'll get map_with_data.end() for both r.first and r.second, so your new_map will end up empty (as you'd probably expect).

If you really wanted to, you could use lower_bound and upper_bound instead of equal_range:

multimap<string, string> new_map {
    map_with_data.lower_bound(string_key), 
    map_with_data.upper_bound(string_key) };

I prefer the code using equal_range though.

Demo code:

#include <map>
#include <string>
#include <iostream>
#include <iterator>

using namespace std;

namespace std {
    ostream &operator<<(ostream &os, pair<string, string> const &p) {
        return os << "(" << p.first << ", " << p.second << ")";
    }
}

int main() {

    multimap<string, string> map_with_data {
        {"A", "B"},
        {"A", "C"},
        {"B", "B"},
        {"B", "C"}
    };

    auto r = map_with_data.equal_range("A");

    multimap<string, string> new_map(r.first, r.second);

    copy(new_map.begin(), new_map.end(), 
        ostream_iterator<pair<string, string>>(std::cout, "\n"));
}

Result:

(A, B)
(A, C)
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • Thanks I'll give this a go. Looks to be a more direct way to accomplish my specific need. – Enigma Mar 17 '15 at 20:03
  • The `auto r` declaration is giving me problems. Do I need a specific c++ std set? – Enigma Mar 17 '15 at 20:10
  • @Enigma: It requires C++11, with gcc or Clang you need `--std=c++11`. – Jerry Coffin Mar 17 '15 at 20:11
  • Ah, had to specify that (`-std=c++11`). Thought it was the default (some messages led me to believe so). – Enigma Mar 17 '15 at 20:15
  • 1
    @Enigma: you have to be really careful--some people build gcc (or probably Clang, but I've seen it with gcc) with it specified by default. Others don't. The default default (so to speak) is that it's not set though. – Jerry Coffin Mar 17 '15 at 20:16