C++ 静态常量std::map<;字符串,int>;如果埃尔塞夫
我写了一个函数,可以将字符串转换成数字。我看到了两种可能的变体:C++ 静态常量std::map<;字符串,int>;如果埃尔塞夫,c++,c++11,if-statement,dictionary,C++,C++11,If Statement,Dictionary,我写了一个函数,可以将字符串转换成数字。我看到了两种可能的变体: int convert(const std::string input) { if (input == "one") { return 1; } else if (input == "two") { return 2; } // etc. return 0; } 或 int转换(常量std::字符串输入){ 静态常量映射表={ {“一”,1}, {“两个”,
int convert(const std::string input) {
if (input == "one") {
return 1;
} else if (input == "two") {
return 2;
}
// etc.
return 0;
}
或
int转换(常量std::字符串输入){
静态常量映射表={
{“一”,1},
{“两个”,2}
//等等。
}
const auto result=table.find(输入);
if(result==table.end())
{
返回0;
}
返回结果->秒;
}
哪种方法更有效/可接受/可读?对于少量可能的输入值,我更希望解决方案1简单明了并且可能具有最佳性能 如果值列表变得太大,那么您真正需要的是整数和写入的数字之间的转换,这真的是另一回事(请参阅NathanOliver评论中引用的“人性化者”库,如果其他An
If else
(或开关
,如果您可用)适用于小案例,您还可以控制测试的顺序,以防最常见的测试可以快速停止搜索,您可以先测试它们
在许多情况下,开关
远远优于if else
s列表。两者都更容易阅读,而且可能更快。尽管开关
不是字符串
的最佳选择
但是,您可以打开枚举
,而不是使用字符串;这当然是更好的方法,除了映射
map
或std::unordered\u map
对于大量可能性,或者当您需要在运行时更新这些可能性时,效果要好得多。对于少量文本,我会使用一个简单的查找表:
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;
}
答案在很大程度上取决于您将支持多少不同的字符串 一些字符串:使用if-else。以后理解代码所需的努力很少 大量字符串:创建映射。与读取大量if-else构造相比,理解代码的工作量很小。您可能需要经常扩展此列表。添加数据需要更少的键入
我不确定C++的映射使用字符串作为键有多聪明。在最坏的情况下,两者都具有相同的性能。如果列表非常大,您可能会考虑创建字符串的哈希值并将其用作键。这可能会大大提高性能。但您必须确保不会发生冲突。(一个好的散列算法和64位散列大小就足够了。)可能是现代map实现已经做到了这一点。我建议
map
。主要原因是它在这个词的两种可能含义上都具有更好的伸缩性
如果将来可能需要添加更多条件,则使用映射更易于维护和管理。此外,它允许运行时修改查找表,这在某些上下文中非常有用
我在开发中遇到了一个类似的问题,像这样的查找必须由子类修改。我认为映射提供了更大的灵活性。映射允许我定义一个虚拟函数,如getLookup()
,它返回一个查找表。在该函数中,我可以保留一个静态映射(我按照第一次调用时需要的方式设置)特定于该类类型。如果您正在考虑此类应用程序,那么我强烈建议映射If链。If链在继承中完全不可管理。您将开始问“如何更改X解析为什么?”迟早会有,除了意大利面之外,没有什么切实可行的答案
另一个评论:考虑。对于这个用例,范围迭代似乎不太可能。
< P>如果在地图搜索O(log n)的情况下,如果否则搜索具有O(n)的复杂性。 而且,当列表变长时,if-else语句将变得不可读。因此,map更好 另一方面,关于函数声明中的参数:int convert(const std::string input)
我会将其更改为通过常量引用传递,而不是通过常量副本传递,以提高效率:
int convert(const std::string& input)
这是其中一个非常适合:
这类似于@Calvin的查找表方法,而不必在多个位置跟踪多组数据
//alphabetically sorted by string X macro
#define MAP_AS_ENUM(e,v,s) MYENUM_##e,
#define MAP_AS_STRING(e,v,s) s,
#define MAP_AS_VALUE(e,v,s) v,
#define MYMAP(OP) \
OP(NONE, -1,"") \
OP(FIVE, 5, "five") \
OP(FOUR, 4, "four") \
OP(ONE, 1, "one") \
OP(THREE, 3, "three") \
OP(TWO, 2, "two") \
OP(ZERO, 0, "zero")
enum myenums{ MYMAP(MAP_AS_ENUM) };
char *mystrings[] = { MYMAP(MAP_AS_STRING) };
char myvalues[]={ MYMAP(MAP_AS_VALUE) };
//now you can use a binary search on mystrings to get the index
//which will correspond to the associated enum
哪种方式更有效/可接受/可读
如果只有两个值,if
/else
解决方案是最有效的,而且肯定非常简单,特别是对于不习惯标准库的人来说,但是它很快就会陷入混乱
因此,当你到达一个5个或更多的项目,切换到使用容器
警告:不幸的是,避免内存分配的std::string_视图
仍然不是标准的;为了简单起见,我将使用std::string
,但如果内存分配是一个问题,std::string_视图
或自定义CStr
类会更好
有3种有效的选择:
和std::map
是最直观的选择,目前还不清楚哪一种更快std::unordered\u map
(排序)总是比std::vector
std::map
int convert(std::string const& name) {
static std::vector<std::pair<std::string, int>> const Table = []() {
std::vector<std::pair<std::string, int>> result = {
{ "one", 1 },
{ "two", 2 },
{ "three", 3 },
{ "four", 4 }
};
std::sort(result.begin(), result.end());
return result;
}();
auto const it =
std::lower_bound(Table.begin(), Table.end(), std::make_pair(name, 0));
if (it != Table.end() and it->first == name) {
return it->second;
}
return 0;
}
int转换(std::string const&name){
静态std::vector const Table=[](){
标准::向量结果={
{“一”,1},
{“两个”,2},
{“三”,3},
{“四”,4}
};
排序(result.begin(),result.end());
返回结果;
}();
自动const it=
std::下限(Table.begin()、Table.end()、std::make_pair(name,0));
if(it!=Table.end()和it->first==name){
返回->秒;
}
返回0;
}
毕竟,排序数组是执行二进制搜索的最有效方式,因为它具有更好的缓存行为。
//alphabetically sorted by string X macro
#define MAP_AS_ENUM(e,v,s) MYENUM_##e,
#define MAP_AS_STRING(e,v,s) s,
#define MAP_AS_VALUE(e,v,s) v,
#define MYMAP(OP) \
OP(NONE, -1,"") \
OP(FIVE, 5, "five") \
OP(FOUR, 4, "four") \
OP(ONE, 1, "one") \
OP(THREE, 3, "three") \
OP(TWO, 2, "two") \
OP(ZERO, 0, "zero")
enum myenums{ MYMAP(MAP_AS_ENUM) };
char *mystrings[] = { MYMAP(MAP_AS_STRING) };
char myvalues[]={ MYMAP(MAP_AS_VALUE) };
//now you can use a binary search on mystrings to get the index
//which will correspond to the associated enum
int convert(std::string const& name) {
static std::vector<std::pair<std::string, int>> const Table = []() {
std::vector<std::pair<std::string, int>> result = {
{ "one", 1 },
{ "two", 2 },
{ "three", 3 },
{ "four", 4 }
};
std::sort(result.begin(), result.end());
return result;
}();
auto const it =
std::lower_bound(Table.begin(), Table.end(), std::make_pair(name, 0));
if (it != Table.end() and it->first == name) {
return it->second;
}
return 0;
}
int convert(const std::string& input) {
static const std::array<std::string, 9> numbers
= {"one", "two", "three", "four", "five", "six", "seven", "eight", "nine"};
auto find_result = std::find(numbers.begin(), numbers.end(), input);
if (find_result == numbers.end())
return 0;
return std::distance(numbers.begin(), find_result) + 1;
}