tags:

views:

291

answers:

4

If I have a map like this:

std::map<char, std::vector<char> > m;
m['A'].push_back('a');
m['A'].push_back('b');
m['A'].push_back('c');
m['B'].push_back('h');
m['B'].push_back('f');

How would I find and delete 'b'? Is this possible?

+6  A: 

Sure, use an iterator:

for (std::map<char, std::vector<char> >::iterator i = m.begin(); i != m.end(); ++i) {
    std::vector<char>::iterator j = std::find(i->second.begin(), i->second.end(), 'b');
    if (j != i->second.end()) {
        i->second.erase(j);
    }
}
Greg Hewgill
+1 Although I might change 'b' to 'B' :)
SwDevMan81
this gives me an error no find identifier not found
Jack Null
The original question has both 'B' and 'b', and specific 'b' as the item to delete. Without more detail, I'm mostly guessing.
Greg Hewgill
@Jack Null: #include <algorithm>
Greg Hewgill
@Greg: std::find
Steve Folly
Good point, if everything else is explicitly qualified then that should be too. Thanks!
Greg Hewgill
+1  A: 

If you expect there can be multiple 'b's in the vector, I would write this way.

for (std::map<char, std::vector<char> >::iterator i = m.begin(); i != m.end(); ++i) {
  i->second.erase(std::remove(i->second.begin(), i->second.end(), 'b'), i->second.end());
}
Kei
I don't think `std::remove()` works on maps, since their `value_type` is a (partly) `const` object and, IIRC, `std::remove()` requires it to be assignable.
sbi
Isn't Jack trying to delete 'b' s in the vector? I'm calling std::remove on the vector (i->second) not the map.
Kei
@Kei: Um, sorry for that brainfart. `<sheepish_look>`
sbi
A: 

I'm only reproducing other people's algorithms here, but I find that without a couple of judicious typedefs and temporary reference variables the extra long lines can become significantly less readable.

The original question doesn't fully specify the required behaviour, but it may be appropriate to remove the map entry if the vector is left empty. This could be done as part of the map iterator, or as a pass at the end.

Also might want the remove the first 'b' in the first vector containing a 'b', or all 'b' in every vector, or some combination.

Remove all the 'b' in all the vectors in the map.

typedef std::map<char, std::vector<char> > MapVecChar;

for( MapVecChar::iterator i = m.begin(); i != m.end(); ++i )
{
    std::vector<char> &v = i->second;
    v.erase( std::remove( v.begin(), v.end(), 'b' ), v.end() );
}

Remove the first 'b' found in a the vector in the map.

typedef std::map<char, std::vector<char> > MapVecChar;

for( MapVecChar::iterator i = m.begin(); i != m.end(); ++i )
{
    std::vector<char> &v = i->second;

    std::vector<char>::iterator j( std::find( v.begin(), v.end(), 'b' ) );

    if( j != v.end() )
    {
        v.erase( j );
        break;
    }
}

Remove empty map entries.

for( MapVecChar::iterator i = m.begin(); i != m.end(); )
{
    if( i->second.empty() )
        m.erase( i++ );
    else
        ++i;
}
Charles Bailey
A: 

why not try boost.bimap?

t.g.
As far as I see it, it seems to me that Jack Null's container authorizes multiple 'b' for the same map Key, as well as multiple 'b' for different map keys. So the bimap is not the same container as Jack Null's.
paercebal
It seems you can achieve it with something like this:typedef bimap< multiset_of<char>, multiset_of<std::vector<char>> > bm_type,The following is copied from <bimap.hpp>For example, a bidirectional map that has multimap semanticsviewed from both sides is defined by specifying that the twokeys sets are of multiset_of<Key> type.This allows the bimap class to support seamingless N-N, 1-N,ordered/unordered and even vector-list types of mapping.
t.g.