3

I am attempting to add a vector to a position in a map according to a key.

vector<string> words;
map<string, vector<string>> wordMap;

for (int i = 0; i < words.size(); i++) {
    string word = words.at(i);

    if (wordMap.find(word) == wordMap.end())
        wordMap.insert(make_pair(word, vector<string>()));

    vector<string> context = { "EMPTY" };

    if (i == 0)
        context = { "Beginning of words", words[i + 1], words[i + 2] };
    else if(i == 1)
        context = { "Beginning of words", words[i - 1], words[i + 1], words[i + 2] };
    else if (i == words.size() - 2)
        context = { words[i - 2], words[i - 1], words[i + 1], "End of words" };
    else if(i == words.size() - 1)
        context = { words[i - 2], words[i - 1], "End of words" };
    else
        context = { words[i - 2], words[i - 1], words[i + 1], words[i + 2] };

    wordMap[word].push_back(context);
    cout << context[0] << endl;
}

I keep getting the following error at the period in

wordMap[word].push_back(context);

Error: no instance of overloaded function "std::vector<_Ty,_Alloc>::push_back[with_Ty=std::string,_Alloc=std::allocator<std::string>]" matches the argument list 
argument types are: (std::vector<std::string, std::allocator<std::string>>) 
object type is std::vector<std::string, std::allocator<std::string>>

Everything else in the program works and I can post it if you need me to, but the only error is when I try to use push_back. I need to use push_back because I cannot reassign the value. I have to keep all previous values located at that key, so push_back is ideal. Any help is greatly appreciated.

Dillon Clapp
  • 150
  • 4
  • 15
  • 1
    Wouldn't 'wordMap[word] = context' instead of 'wordMap[word].push_back(context)' do? Or can you be a bit more clear about what you are trying to achieve? – marco6 Apr 19 '16 at 21:19
  • 1
    oh nm, I read that wrong. You are trying to push a `vector` onto a `vector`. You need a string as an argument. Could you make context a stringstream, add things as you go, then just do a `wordMap[word].push_back(context.str());`? – RyanP Apr 19 '16 at 21:23
  • @RyanP Basically I am taking a large amount of text and separate each word into a map. This eliminates duplicates, but the vector is used to hold the two words before and after the keyword. So I would need to push new "contexts" of the word into the map value. – Dillon Clapp Apr 19 '16 at 21:24
  • 2
    `std::copy(context.begin(), context.end(), std::back_inserter(wordMap[word]));` should do it (`#include ` and `#include `). – Max Lybbert Apr 19 '16 at 21:28
  • 2
    Note code with `wordMap.find(word) ...` is completely redundant and can be removed. – Slava Apr 19 '16 at 21:35
  • Well than even context could be. He could just add words to wordMap[word] instead of copying them around... – marco6 Apr 19 '16 at 21:37
  • before doing `words[i + 2]` you should check that entry actually exists – M.M Apr 19 '16 at 23:11

2 Answers2

10

Instead of:

wordMap[word].push_back(context);

you should append new vector:

std::copy(context.begin(), context.end(), std::back_inserter(wordMap[word]));

another thing is that you dont really need this initialization:

if (wordMap.find(word) == wordMap.end())
        wordMap.insert(make_pair(word, vector<string>()));

as later on wordMap[word] will add value initialized element.

When operator[] is called on map instance then if no value is present at given key, a new element is always added, then reference to it is returned.

marcinj
  • 48,511
  • 9
  • 79
  • 100
  • 1
    [link to further reading on concatenating vectors](http://stackoverflow.com/questions/3177241/what-is-the-best-way-to-concatenate-two-vectors?rq=1) – M.M Apr 19 '16 at 23:12
-1

Edit: the issue happens because wordMap[word] is of the type vector<string> and calling push_back is correct, but you need to supply a value of type string to push_back but here wordMap[word].push_back(context);, the type of context is vector<string>.

Perhaps change is like so:

for(vector<string>::iterator iter = context.begin(); iter != context.end(); iter++) {
    wordMap[word].push_back(*iter);
}

Also, I would use pointers instead since might be better to store a pointer to a vector of strings in heap instead of in the stack ex:

map<string, vector<string>*> wordMap;
...
vector<string>* context = new vector<string>();
...
wordMap[word] = context;
ArmenB
  • 2,125
  • 3
  • 23
  • 47
  • That could certainly get messy as you would have to make sure `map`'s destructor would properly dispose of the vectors. (Otherwise, you would have to keep track of them separately, and then have to be storing the same information twice. ) – Lilith Daemon Apr 19 '16 at 21:38
  • well the maps destructor wouldn't destroy the vectors, you have to deallocate them in the class destructor prior to maps destruction. So the parent class or function that's holding the map should destroy all vectors in the map. – ArmenB Apr 19 '16 at 21:40
  • At the very least this should be `wordMap[word] = context` as a map doesn't have push_back method. Still I would never do such a thing and it doesn't solve the problem of the question as I have understood it. – marco6 Apr 19 '16 at 21:42
  • that's correct, I fixed it. It might not solve the problem but it's a method that I have used before and it works well since it's using heap now instead of the stack so more space and keeping a local reference to the vector is easier to do. There is noting wrong with this method, just another way of doing things. – ArmenB Apr 19 '16 at 21:46