是否有更惯用的方法将 "insert or accumulate" 转换为 unordered_map 表示项目计数?

Is there a more idiomatic way to "insert or accumulate" into an unordered_map representing item counts?

考虑如下代码:

#include <iostream>
#include <unordered_map>

std::unordered_map<char, int> get_letter_frequencies(const std::string& str) {
    std::unordered_map<char, int> freqs;
    for (char ch : str) {
        auto iter = freqs.find(ch);
        if (iter == freqs.end()) {
            freqs[ch] = 1;
        } else {
            iter->second++;
        }
    }
    return freqs;
}

int main()
{
    std::string str = "AABBDBCABDA";
    auto freqs = get_letter_frequencies(str);
    std::cout << freqs['B'] << "\n";

    return 0;
}

将字母数存储在 unordered_map 中。我的问题是是否有一段 terser/more 惯用代码可以用来替换

auto iter = freqs.find(ch);
if (iter == freqs.end()) {
    freqs[ch] = 1;
} else {
    iter->second++;
}

我可以写一个函数 insert_or_accumulate( ... ) 但它看起来有点过分了。

就这样:

for (char ch : str) {
    ++freqs[ch];
}

只需访问 freqs[ch] 即可创建键值对(如果缺少),使用默认构造函数(对于 int,这使得 0)和 returns对值(新的或现有的)的引用,因此 ++freqs[ch] 将增加现有值,同时创建和增加缺失值。

注意:我偏好使用前缀 ++;这在这里无关紧要,因为我们正在递增原始内置类型,但在 C++ 中,您希望养成默认使用前缀递增的习惯,因为 类 重载递增 不能 像前缀增量一样有效地实现后缀增量(后缀需要制作实例的副本,前缀可以在没有副本的情况下运行)。

考虑到动态分配和散列的数量,使用 std::unordered_map 本身有点矫枉过正。当然,迭代非零元素既快速又容易,但是计算字符的更简单方法是使用一个包含 256 个值的简单数组。

数组更简单,而且很可能更快,但代价是 可能 如果您想这样做的话,可能会更麻烦地遍历项目。但是,考虑到 unordered_map 会发生的间接性,我个人仍然更喜欢这种方法。也订了。

int freqs[256] = {};
for (unsigned char c : str) ++freqs[ch];

作为 returns 值的函数的插入,您可以使用 std::array.

#include <array>
#include <string>
#include <iostream>

typedef std::array<int, 256> CharFreqType;

CharFreqType get_letter_frequencies(const std::string& str)
{
    CharFreqType freqs{};
    for (unsigned char c : str) ++freqs[c];
    return freqs;
}

int main()
{
    auto freqs = get_letter_frequencies("AABBDBCABDA");
    std::cout << freqs['B'] << "\n";
}