首先我们都知道map的operator[]
可以通过key值找到对应的value值。
成员类型 | 含义 |
---|---|
key_type | The first template parameter (Key) |
mapped_type | The second template parameter (T) |
value_type | pair |
那么这里我们了解一下operator[]
的底层实现,直接看可能有点迷:
那我们可以发现其实operator[]
底层是用insert来实现的。
那么inset的返回值又是什么呢?我们一起来看看:
pair<iterator,bool> insert (const value_type& val);
查cplusplus网站阅读insert的返回值(大家可以自己理解一哈):The single element versions (1) return a pair, with its member pair::first set to an iterator pointing to either the newly inserted element or to the element with an equivalent key in the map. The pair::second element in the pair is set to true if a new element was inserted or false if an equivalent key already existed.
我们发现inset的返回值其实是一个pair,这个pair的key值其实是一个迭代器,这个迭代器是指向新插入这个位置的迭代器,value值其实是一个bool值,表示插入成功还是失败,原来没有这个key值插入会成功返回true,已经存在这个key值插入会失败,返回false。
那么再回来!我们再看看这个operator[]
的底层实现,并添加一个栗子:
(红色框框)首先这里创建了一个pair,这个pair的key值为传参传过来的k,value是一个mapped_type的value,暂时为空待定。
(绿色框框)调用insert插入这个pair。插入这个pair会返回一个pair。pair的第一个值就是这个位置的迭代器,但是因为这个key值已经存在了,因此pair的value为false。
(粉色框框)this指针取到这个pair的first,就是我们刚刚看到的insert的返回值pair的key值,也就是插入位置的迭代器。
最后解引用之后再取到这个位置的second值,也就是这个位置的value值。然后函数的返回值为mapped_type的引用。
综上所述,operator[]
返回的是这个key值所对应的value的引用。因此operator[]
可以通过key值找到对应的value值,然后对这个value值进行修改操作。
举个栗子:
前情提要:dict是一个 map
dict.insert({ "left", "左边" });
dict["left"] = "剩余";
栗子中就是这样的:“left”这个key值已经存在,因此insert返回的是这个位置的迭代器和一个false(false是因为key值存在插入失败),取到这个迭代器,然后解引用取到迭代器的second,也就是value并返回value的引用,因此dict["left"]
返回的就是"左边"这个字符串的引用,那么在执行赋值操作,也就是改变了这个“left”所对应的value值,此时“left”的value值就变成了“剩余”。
那么operator[]
又可以完成数据的插入,这又是怎么实现的鸭????
那么不要急,我们继续分析operator[]
的底层实现ヾ(●´∀`●)
当我们传过来的key值是map里没有的,那么这里创建了一个pair,这个pair的key值就是我传过来的key值,但是此时这里的mapped_type的value,暂时为空待定。调用了insert,因为这个key值没有,所以完成了插入,insert的返回值为新插入这个位置的迭代器和true(true表示插入成功),然后取到这个迭代器,解引用之后拿到这个key值的value(此时value值为空),返回的就是这个空的value。
举两个栗子:
前情提要:dict是一个 map
dict["banana"];
如上就是插入了一个key为“banana”,value为“\0”的一个pair。
dict["key"] = "关键字";
如上,首先经过dict["key"]
之后,就成功插入了一个key值为“key”,value为“\0”的一个pair,返回值是“\0”的引用,然后在赋值操作,也就是将“\0”变成了“关键字”,这样就完成了一个pair的插入。
总结一下:operator[]
可以查找到对应key值的value,如果key值没有的话,也可以进行插入操作。
统计每种水果出现的次数
“苹果”, “苹果”, “梨”, “苹果”, “香蕉”, “梨”, “香蕉”, “香蕉”, “苹果”, "西瓜"
有以下三种解决方法:
定义一个map,类型为map
去寻找字符串在不在这个map中,如果这个水果在,那么直接给这个pair的second++,如果不在,就插入这个水果,把second设置为1。
string str[] = { "苹果", "苹果", "梨", "苹果", "香蕉", "梨", "香蕉", "香蕉", "苹果", "西瓜" };
map<string, int> count_map;
for (const auto &s : str)
{
auto tmp = count_map.find(s);
if (tmp != count_map.end())
{
tmp->second++;
}
else
{
count_map.insert({ s, 1 });//返回的是pair
}
}
for (const auto &e : count_map)
{
cout << e.first << ":" << e.second << endl;
}
定义一个map,类型为map
因为insert的返回值中value是一个bool,表示插入成功还是失败,所以我们直接插入这个水果和1(表示这个水果出现了一次)。我们可以通过这个bool值判断这个水果在不在这个map里。如果在,那么insert的返回值的value是一个false,那么直接利用inset的返回值中的key(对应位置的迭代器)找到对应位置的value,直接++即可。如果不在那么insert的返回值的value是一个true,此时就完后了这个水果和1次的插入。
string str[] = { "苹果", "苹果", "梨", "苹果", "香蕉", "梨", "香蕉", "香蕉", "苹果", "西瓜" };
map<string, int> count_map;
for (const auto &s : str)
{
pair<map<string,int>::iterator ,bool> ret = count_map.insert(pair<string, int>(s, 1));
if (!ret.second)
{
(ret.first)->second++;
}
}
for (const auto &e : count_map)
{
cout << e.first << ":" << e.second << endl;
}
定义一个map,类型为map
我们可以利用这个operator[]
来解决这个问题,代码非常简单。
直接遍历这个水果字符串数组,然后调用operator[]
,因为operator[]
有就返回value的引用,没有就插入之后返回value的引用,那么当遍历这些水果的时候,如果这个水果在,那么直接给value++,如果这个水果不在,那么返回的是0的引用,直接++就变成了1,表示出现一次,后序在插入同样的水果时,插入失败,直接给value++,逻辑也没有任何问题,因此这个方法最为简单,推荐~
string str[] = { "苹果", "苹果", "梨", "苹果", "香蕉", "梨", "香蕉", "香蕉", "苹果", "西瓜" };
map<string, int> count_map;
for (auto s : str)
{
count_map[s]++;
}
for (const auto &e : count_map)
{
cout << e.first << ":" << e.second << endl;
}