在C ++中实现计数器时映射构造函数

时间:2018-03-20 08:25:30

标签: c++ dictionary stl counter

我现在正在用c ++尝试STL,并发现了一个我不明白的问题。 我想象一个问题需要显示每个元素以及它在向量中出现的次数。由于我知道如何使用vector来完成这个问题,我尝试使用" set"或"地图"解决问题。

vector<char> v{ 'a', 'b', 'f', 'b', 'd', 'c', 'b', 'f', 's', 'v', 'x'};
map<char, int> m; // <key, counter>
for (char n : v)
    m.insert(pair<char, int>(n, m[n]+1));

我认为每次发现密钥时它都会产生计数器加,但是,计数器没有工作,每个计数器都是0。 经过一些改变后:

vector<char> v{ 'a', 'b', 'f', 'b', 'd', 'c', 'b', 'f', 's', 'v', 'x'};
map<char, int> m; // <key, counter>
for (char n : v)
    m.insert(pair<char, int>(n, m[n]++));

然后它工作。我不知道为什么。

2 个答案:

答案 0 :(得分:2)

首先,您通过调用insert更新地图条目的尝试都将被忽略,因为如果条目已存在,insert不会执行任何操作。引用C++ reference

  

如果容器尚未包含具有等效键的元素,则将元素插入容器中。

如果你稍微重写一下你的代码会更清楚一点:

for (char n : v)
{
    int& count = m[n];
    int new_count = count + 1;
    pair<char, int> p(n, new_count);
    m.insert(p); // ignored because the key already exists
}

第二个版本会直接修改地图内的计数,因为operator[]会将引用返回到存储的值,而{{1直接操纵operator++。您的第二个版本将重新显示如下:

int

即使您再次忽略尝试在地图中插入新对,但由于您直接修改了地图中存储的值,因此第二个版本会首先执行您希望代码执行的操作

答案 1 :(得分:1)

仔细查看insert函数:它只插入一个元素(如果尚未找到)!

相比之下,index operator会更新一个元素(如果找到),并创建一个具有默认值的新元素。

所以:

m.insert(pair<char, int>(n, m[n]+1));

第一次调用它时,m[n]已创建一个默认值为0的元素。然后,您在地图上调用insert,但由于已找到该键,因此未插入任何对。所以你总是得到0 ......

m.insert(pair<char, int>(n, m[n]++));

实际上,从insert看,没有区别:地图中的条目是在您第一次访问位置n的地图时创建的,并且您可以直接递增条目。 insert本身从不实际插入一对......

所以,如果你切断了&#34;什么都不做&#34;一段代码,剩下的就是:

for (char n : v)
    m[n]++;

为了更好地理解,使用insert的变体等同于上面的代码示例:

for (char n : v)
    (m.insert(std::pair<char, int>(n, 0)).first->second)++;

有趣,不是吗?把它分成几块:

for (char n : v)
{
    std::pair<std::map<char, int>::iterator, bool> result = m.insert(std::pair<char, int>(n, 0));
    std::pair<char const, int>& entry = *result.first;
    entry.second++;
}

这一行的核心部分是:

std::pair<std::map<char, int>::iterator, bool> result = m.insert(std::pair<char, int>(n, 0));

如果实际插入了元素,则该对的bool设置为true,否则设置为false。由于对特定情况下的这条信息不感兴趣,因此不再使用。

迭代器指向地图中的元素 - 新创建的元素(bool部分为true)或已找到的元素(bool部分为false)。