107

How to update the value of a key in std::map after using the find method?

I have a map and iterator declaration like this:

map <char, int> m1;
map <char, int>::iterator m1_it;
typedef pair <char, int> count_pair;

I'm using the map to store the number of occurrences of a character.

I'm using Visual C++ 2010.

Smi
  • 13,850
  • 9
  • 56
  • 64
jaykumarark
  • 2,359
  • 6
  • 35
  • 53

6 Answers6

155

std::map::find returns an iterator to the found element (or to the end() if the element was not found). So long as the map is not const, you can modify the element pointed to by the iterator:

std::map<char, int> m;
m.insert(std::make_pair('c', 0));  // c is for cookie

std::map<char, int>::iterator it = m.find('c'); 
if (it != m.end())
    it->second = 42;
James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • 2
    Thanks. Is it also possible to use the [] operator? – jaykumarark Dec 24 '10 at 18:14
  • 1
    @Jay: Yes, but the behavior is different. See [the `map` documentation](http://www.sgi.com/tech/stl/Map.html) for the various functions provided by `map`. – James McNellis Dec 24 '10 at 18:14
  • 3
    I got `error: assignment of member 'std::pair::second' in read-only object` :( – The Student Jul 29 '14 at 15:51
  • 1
    @jaykumarark I think yes, but disadvantage of this solution is, map must find the location of item second time (first time is your call of find method) which is operation with log(N) complexity. It is unecessary duplication of same operation. – truthseeker May 13 '16 at 13:36
65

I would use the operator[].

map <char, int> m1;

m1['G'] ++;  // If the element 'G' does not exist then it is created and 
             // initialized to zero. A reference to the internal value
             // is returned. so that the ++ operator can be applied.

// If 'G' did not exist it now exist and is 1.
// If 'G' had a value of 'n' it now has a value of 'n+1'

So using this technique it becomes really easy to read all the character from a stream and count them:

map <char, int>                m1;
std::ifstream                  file("Plop");
std::istreambuf_iterator<char> end;

for(std::istreambuf_iterator<char> loop(file); loop != end; ++loop)
{
    ++m1[*loop]; // prefer prefix increment out of habbit
}
Martin York
  • 257,169
  • 86
  • 333
  • 562
  • 4
    Your answer is great for the *actual question* -- sadly the asker missed to ask (and therefore accept) this in an obvious way. That's why I think it would be even better to have a short statement about this fact: people who "read" very fast, might believe that you are suggesting to use `[]` after having used `find` (I don't think that this was your intention). – Wolf May 04 '16 at 12:04
  • Well, I think 'find' can be better if one does not want to *implicitly* insert an element. Derefercing 'find' and dying by SIGSEGV can be preferrable. – Gwangmu Lee Jul 06 '17 at 17:15
  • 3
    @GwangmuLee De-referencing the `end()` iterator is undefined behavior it does not need to generate a `SIGSEGV` (and in my experience it is unlikely to do so). – Martin York Jul 06 '17 at 20:51
10

You can use std::map::at member function, it returns a reference to the mapped value of the element identified with key k.

std::map<char,int> mymap = {
                               { 'a', 0 },
                               { 'b', 0 },
                           };

  mymap.at('a') = 10;
  mymap.at('b') = 20;
Manish Sogi
  • 201
  • 2
  • 7
2

You can update the value like following

   auto itr = m.find('ch'); 
     if (itr != m.end()){
           (*itr).second = 98;
     }
ZAFIR AHMAD
  • 79
  • 1
  • 3
1

You can also do like this-

 std::map<char, int>::iterator it = m.find('c'); 
 if (it != m.end())
 (*it).second = 42;
chunky
  • 75
  • 1
  • 2
  • 11
1

If you already know the key, you can directly update the value at that key using m[key] = new_value

Here is a sample code that might help:

map<int, int> m;

for(int i=0; i<5; i++)
    m[i] = i;

for(auto it=m.begin(); it!=m.end(); it++)
    cout<<it->second<<" ";
//Output: 0 1 2 3 4

m[4] = 7;  //updating value at key 4 here

cout<<"\n"; //Change line

for(auto it=m.begin(); it!=m.end(); it++)
    cout<<it->second<<" ";
// Output: 0 1 2 3 7    
abhinav1602
  • 1,190
  • 17
  • 18
  • 2
    unless the *only* thing you want to do is to updated the value, and you are already certain that the key exists (or you don't care if a new key gets created), you don't want to use this strategy. Kind of a narrow application. In almost all cases, you are better off doing a map::find() first, getting an iterator and updating iterator->second, as the other answers proposed. – alex gimenez May 25 '21 at 10:24