static const std :: map <string,int> vs if-elseif

Ale*_*lex 22 c++ dictionary if-statement c++11

我写了一个应该将字符串转换为数字的函数.我看到两种可能的变体来写它:

int convert(const std::string input) {
    if (input == "one") {
        return 1;
    } else if (input == "two") {
        return 2;
    }
    // etc.
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

要么

int convert(const std::string input) {
    static const map<string, int> table = {
        {"one", 1},
        {"two", 2}
        // etc.
    }

    const auto result = table.find(input);

    if (result == table.end())
    {
        return 0;
    }

    return result->second;
}
Run Code Online (Sandbox Code Playgroud)

哪种方式更有效/可接受/可读?

phi*_*ipp 21

答案很大程度上取决于你将支持多少不同的字符串.

一些字符串:与if-else一起使用.稍后理解代码所需的努力很少.

很多字符串:创建一个地图.与阅读巨大的if-else结构的努力相比,理解代码的努力很小.可能,您必须经常扩展此列表.添加数据需要更少的输入.

我不确定C++的地图是如何使用字符串作为键的.在最坏的情况下,两者都具有相同的性能.如果列表变得非常庞大,您可能会想到创建字符串的哈希值并将其用作键.这可能会大大提高性能.你必须确保不会发生碰撞.(良好的散列算法和64位散列大小应该足够了.)可能现代地图实现已经这样做了.

  • 大多数C++`std :: map`实现使用二进制搜索,而`std :: unordered_map`使用哈希表(哈希函数可以自定义). (10认同)
  • @Calvin作为迂腐地图通常被实现为红黑树(这是一种自平衡二分搜索树.)访问元素的时间复杂度是地图大小的对数.平均而言,哈希表是"O(1)"最坏的情况,它可能是"O(n)"(如果你使用相同的密钥,这不是这个问题的情况) (2认同)

Non*_*upt 8

对于一小组文本,我使用一个简单的查找表:

struct LookupTable {
    const char* text;
    int value;
};
const LookupTable table[] = {
    { "one", 1 },
    { "two", 2 }
};
int convert(const char* text) {
    if (!text) return 0;
    for (int i=0; i<sizeof(table)/sizeof(LookupTable); i++) {
        if (strcasecmp(text, table[i].text) == 0 ) {
            return table[i].value;
        }
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

对于大量文本,我会考虑使用std::unordered_map<std::string,int>,也许是自定义散列函数(bkdr散列或elf散列对单词很好).


编辑:正如大卫在评论中指出的那样,如果你不想要丑陋sizeof,请使用现代的for循环:

int convert(const char* text) {
    if (!text) return 0;
    for (auto& entry: table) {
        if (strcasecmp(text, entry.text) == 0 ) {
            return entry.value;
        }
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

  • `std :: array`或`std :: vector`几乎肯定比C数组好,并且使用`sizeof`,现代C++中几乎不需要它 (10认同)
  • 当`std :: map`足够时,为什么要经历创建`LookupTable`的麻烦? (4认同)
  • `for(auto&i:table){if(!strcmp(text,i.text))返回i.value; }` (2认同)

joh*_*ers 6

一个if-else(或者switch,如果可用的话)适用于小案例,并且您还可以控制测试的顺序,以防最常见的测试可以快速切断搜索,您可以先测试它们.

在许多情况下,a switch远比if-elses 列表好.两者都更容易阅读,也可能更快.虽然switch不是最好的选择string.

然而,您可以打开enum而不是使用字符串; 这当然是更好的方法,除了a map.

对于大量可能性或者在运行时需要更新这些可能性时,A map或者std::unordered_map更好.

  • 你不能在字符串中使用`switch`,所以我认为在他们的特殊情况下并不是更好. (3认同)