Как обновить std :: map после использования метода find?

92

Как обновить значение ключа std::mapпосле использования findметода?

У меня есть объявление карты и итератора, подобное этому:

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

Я использую карту для хранения количества вхождений символа.

Я использую Visual C ++ 2010.

Jaykumarark
источник

Ответы:

133

std::map::findвозвращает итератор к найденному элементу (или к, end()если элемент не был найден). Пока mapне является константой, вы можете изменить элемент, на который указывает итератор:

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;
Джеймс МакНеллис
источник
2
Благодарю. Можно ли также использовать оператор []?
jaykumarark
1
@ Джей: Да, но поведение другое. Смотрите в mapдокументации для различных функций , предоставляемых map.
Джеймс МакНеллис,
3
Я получил error: assignment of member 'std::pair<char* const, char*>::second' in read-only object:(
Том Брито
1
@jaykumarark Я думаю, что да, но недостатком этого решения является то, что карта должна находить местоположение элемента во второй раз (первый раз - это ваш вызов метода поиска), что является операцией со сложностью журнала (N). Это ненужное дублирование одной и той же операции.
Искатель правды
52

Я бы использовал оператор [].

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'

Таким образом, используя эту технику, становится действительно легко прочитать все символы из потока и пересчитать их:

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
}
Мартин Йорк
источник
3
Ваш ответ отлично подходит для реального вопроса - к сожалению, спрашивающий упустил возможность задать (и, следовательно, принять) это очевидным образом. Вот почему я думаю, что было бы даже лучше сделать краткое заявление об этом факте: люди, которые «читают» очень быстро, могут подумать, что вы предлагаете использовать, []после использования find(я не думаю, что это было вашим намерением).
Wolf
Что ж, я думаю, что «найти» может быть лучше, если кто-то не хочет неявно вставлять элемент. Может быть предпочтительнее разыменовать «найти» и умереть с помощью SIGSEGV.
Квангму Ли 06
1
@GwangmuLee Отмена ссылки на end()итератор - это неопределенное поведение, ему не нужно генерировать SIGSEGV(и, по моему опыту, это маловероятно).
Martin York
5

Вы можете использовать std::map::atфункцию-член, она возвращает ссылку на сопоставленное значение элемента, идентифицированного с помощью ключа k.

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

  mymap.at('a') = 10;
  mymap.at('b') = 20;
Маниш Соги
источник
1

Если вы уже знаете ключ, вы можете напрямую обновить значение этого ключа, используя m[key] = new_value

Вот пример кода, который может помочь:

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
источник
0

Вы также можете сделать это -

 std::map<char, int>::iterator it = m.find('c'); 
 if (it != m.end())
 (*it).second = 42;
коренастый
источник
0

Вы можете обновить значение следующим образом

   auto itr = m.find('ch'); 
     if (itr != m.end()){
           (*itr).second = 98;
     }
ЗАФИР АХМАД
источник