tags:

views:

136

answers:

4

In code below:

map<string,vector<int>> create(ifstream& in, const vector<string>& vec)
{
    /*holds string and line numbers into which each string appears*/
    typedef map<string,vector<int>> myMap;
    typedef vector<string>::const_iterator const_iter;

    myMap result;
    string tmp;
    unsigned int lineCounter = 0;

    while(std::getline(in,tmp))
    {
        const_iter beg = vec.begin();
        const_iter end = vec.end();

        while (beg < end)
        {
            if ( tmp.find(*beg) != string::npos)
            {   
                result[*beg].push_back(lineCounter);//THIS IS THE LINE I'M ASKING FOR
            }
            ++beg;
        }

        ++lineCounter;
    }

    return result;
}

How should I do it (check line commented in code) if I want to use insert method of map instead of using operator[]?
Thank you.

+1  A: 

map::insert returns a pair containing an iterator to the element (either the one just inserted or the existing one with that key) and a boolean indicating success or failure. You can then call iter->push_back(lineCounter) to add the new line number to the vector.

...and when you're done with all that, realize that this is exactly what operator[] does for you.

Kristo
+1  A: 
result.insert(pair<string,vector<int>>(*beg,100), vector<int>());
result[*beg].push_back(lineCounter);

This is more complicated (but slower too :-) than your current code, since that achieves two things with a single statement: (implicitly) inserts an empty array into the map, then adds a new element to the array.

Péter Török
+1  A: 

See the bottom of this page for an example

Alex
+3  A: 

Seriously, I would not do it.

You are only going to complicate your code unnecessarily. You would need a call to the insert to generate the new element in the map and then modify it.

Just for the sake of it (avoiding the double lookup, but building an unnecessary empty vector):

result.insert( std::make_pair( *beg, std::vector<int>() ) )
      .first->second.push_back( lineCounter );

EDIT: Real equivalent (functionality and performance):

std::map<std::string,std::vector<int> >::iterator it = result.upper_bound( *beg );
if ( it->first != *beg ) {
   it = result.insert( it, std::make_pair( *beg, std::vector<int>() ) ).first;
}
it->second.push_back( lineCounter );
David Rodríguez - dribeas
Actually, you would want to look up the element first, to determine whether you want to do an insert or an update. However, if you do call `insert(pair<Key, Value>)`, it will return the iterator where it was inserted. So there is no lookup needed afterwards.
MSalters
@David I wouldn't do that I just wanted to know how to do it.
There is nothing we can do
@MSalters: I don't know whether the comment is for a previous version of the answer that I had. At any rate you have to choose between two bad options: on the one hand you do `find` followed by `insert` if the element is not present (which requires two lookups for each newly inserted element), on the other hand you do an insert with an empty vector that would perform a single lookup but will unnecessarily create a vector for the cases where the element actually exists.
David Rodríguez - dribeas
Indeed was a previous version, please disregard. About the current version: `insert()` accepts a hint, so that would not require a second lookup. So you could do `result.insert(lowerBoundHint, std::make_pair( *beg, std::vector<int>(1, lineCounter) ) );`
MSalters
I have added that version (somehow I missed the `insert(iterator,value)` from the map docs, and I did look for it). I have used `upper_bound` as I am more comfortable iwth it, and the fact is that with bidirectional iterators hinting with the previous or next will be about the same.
David Rodríguez - dribeas