Como atualizar std :: map depois de usar o método find?

92

Como atualizar o valor de uma chave std::mapapós usar o findmétodo?

Eu tenho um mapa e declaração de iterador como este:

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

Estou usando o mapa para armazenar o número de ocorrências de um personagem.

Estou usando o Visual C ++ 2010.

Jaykumarark
fonte

Respostas:

133

std::map::findretorna um iterador para o elemento encontrado (ou para o end()se o elemento não foi encontrado). Contanto que mapnão seja const, você pode modificar o elemento apontado pelo iterador:

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
fonte
2
Obrigado. Também é possível usar o operador []?
jaykumarark
1
@Jay: Sim, mas o comportamento é diferente. Consulte a mapdocumentação para as várias funções fornecidas por map.
James McNellis
3
Recebi error: assignment of member 'std::pair<char* const, char*>::second' in read-only object:(
Tom Brito
1
@jaykumarark Acho que sim, mas a desvantagem dessa solução é que o mapa deve encontrar a localização do item pela segunda vez (a primeira vez é sua chamada do método de localização), que é uma operação com complexidade log (N). É a duplicação desnecessária da mesma operação.
trueseeker
52

Eu usaria a operadora [].

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'

Então, usando essa técnica, torna-se realmente fácil ler todos os personagens de um fluxo e contá-los:

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
fonte
3
Sua resposta é ótima para a pergunta real - infelizmente, quem fez a pergunta não perguntou (e, portanto, aceitou) de maneira óbvia. Por isso acho que seria ainda melhor fazer uma breve afirmação sobre este fato: as pessoas que "lêem" muito rápido, podem acreditar que você está sugerindo usar []depois de usar find(não acho que tenha sido essa a sua intenção).
Wolf
Bem, acho que 'localizar' pode ser melhor se não se quiser inserir um elemento implicitamente . Cancelar a referência de 'encontrar' e morrer por SIGSEGV pode ser preferível.
Gwangmu Lee
1
@GwangmuLee Cancelar a referência do end()iterador é um comportamento indefinido que não precisa gerar um SIGSEGV(e, em minha experiência, é improvável que o faça).
Martin York
5

Você pode usar a std::map::atfunção de membro, ela retorna uma referência ao valor mapeado do elemento identificado com a chave k.

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

  mymap.at('a') = 10;
  mymap.at('b') = 20;
Manish Sogi
fonte
1

Se você já conhece a chave, pode atualizar diretamente o valor nessa chave usando m[key] = new_value

Aqui está um código de amostra que pode ajudar:

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
fonte
0

Você também pode fazer assim-

 std::map<char, int>::iterator it = m.find('c'); 
 if (it != m.end())
 (*it).second = 42;
robusto
fonte
0

Você pode atualizar o valor da seguinte forma

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