由于python语法的简洁,所以在写c代码的时候,有时候也会想能不能把C代码写的更简练一点,这几天遇到一个,给大家分享一下。 比如我们要用C写一个判断语句,然后根据不同的值返回不同的内容。
if(1 == val) { return "this is one"; } else if(2 == val) { return "this is two"; } else if(3 == val) { return "this is three"; }
如果判断的逻辑很多,代码就会显得很臃肿(文中的例子用switch也可以,但是也还是很难看),如果用python,就会这样写(为了和C类比,这里没有用字典):
datas = [ (1,"this is one"),(2,"this is two"),(3,"this is three") ] for v in datas: if v[0] == val: return v[1]
那在c里面是否能同样的方法实现呢,是可以的:
struct { int key; string strdata; }arr_datas[]={ {1,"this is one"}, {2,"this is two"}, {3,"this is three"}, }; for (i = 0; i < 3; i++) { if (arr_datas[i].key == val) { return arr_datas[i].strdata; } }
附: 有人可能想到用stl的map,查找速度会快一些,不过想到定义一个map,然后调用一堆insert其实也挺麻烦的,而且例子中用的是int,但是并不是所有的类型都是可hash的,所以有些情况下map并不能胜任。
miles on #
我觉得还不如原来的写法呢。。。
Reply
Dante on #
呃,这个。。。你可以想想一下有10个返回码,分别要来返回不同的值。。
就需要写10个if else,而且很不容易维护。
Reply
miles on #
好吧。。。。
Reply
Pinepara on #
这是一种很常用的设计模式,有一个名字叫做 “table-driven”——表驱动法
Reply
Dante on #
原来如此,在python里面经常这样写,不知道原来还有这样一个定义。
Reply
Pinepara on #
《Code Complete》(代码大全)里面有详细的介绍
Reply
Dante on #
看来有必要好好读一下。。一直放在硬盘里。。
Reply
madper on #
lisp常用表驱动法的...抽空看看sicp应该也挺好的, 虽然我没看这本...
Reply
dormouse on #
这样的比较有什么实际用途吗?Python是不是用C写出的?如果是,那么Python的任何用法都可以用C来实现。盘古开天据说用的是C,你信不:-》
Reply
Dante on #
呵呵,言重了,我python和C都用,还用php,只是个人喜好而已~ 大家选择自己喜欢的就行~
Reply
lihex on #
用map我会这么写,光初始化就很麻烦,呵呵
map amap;
string str[3]={"333","222","444"}
int i=0;
while(i<3)
{
amap[i]=str[i++];
}
Reply
greatghoul on #
除了维护外,语法和逻辑上似乎都变复杂了。这种写法可不可取,还得两说。
如果情况比较少,感觉没有必要这么折腾,如果情况比较多,这么多重复的事,干嘛不写成函数。
我个人觉得没有必要为了简化而简化。用爱因思坦那货的话来说"Make everything as simple as possible, but not simpler." 过犹不及
Reply
Dante on #
这是我用这个方法写的统计时间段的函数:
string get_maptime(int time_ms)
{
struct
{
int iTime;
string strTimeKey;
}arr_times[]={
{5,"[0,5]"},
{10,"(5,10]"},
{50,"(10,50]"},
{100,"(50,100]"},
{200,"(100,200]"},
{500,"(200,500]"},
{1000,"(500,1000]"},
{-1,"(1000,~)"},
};
int count = sizeof(arr_times) / sizeof(arr_times[0]);
for (int i = 0; i < count; i++)
{
if (arr_times[i].iTime == -1 || time_ms <= arr_times[i].iTime)
{
return arr_times[i].strTimeKey;
}
}
return "(1000,~)";//实际上到不了这一步
}
Reply
madper on #
逻辑上会变得比较简单吧, 如果是老一辈的程序员, 应该会很喜欢表驱动的方法.
Reply
iCyOMiK on #
谢谢,分享,不错。
Reply
osily on #
如果val只是从1到n这样的,一个元组就可以了,如果不是显然用字典好些,不然凭空提到复杂度,代码也不简洁。
c中也是,应该先考虑数组。其实这总情况用switch就很正常的,没人会说用switch臃肿。
c++中除了数组,map可以应对更多情况。stl里的map不是用hash实现的,而是红黑树,是基于比较排序的。而python的map是用hash实现的。
Reply
Dante on #
这是我用这个方法写的统计时间段的函数:
string get_maptime(int time_ms)
{
struct
{
int iTime;
string strTimeKey;
}arr_times[]={
{5,”[0,5]“},
{10,”(5,10]”},
{50,”(10,50]”},
{100,”(50,100]”},
{200,”(100,200]”},
{500,”(200,500]”},
{1000,”(500,1000]”},
{-1,”(1000,~)”},
};
int count = sizeof(arr_times) / sizeof(arr_times[0]);
for (int i = 0; i < count; i++)
{
if (arr_times[i].iTime == -1 || time_ms <= arr_times[i].iTime)
{
return arr_times[i].strTimeKey;
}
}
return “(1000,~)”;//实际上到不了这一步
}
其实主要是因为这个函数而写了这篇文章,可能文中的例子没有举好,让大家偏向map进行讨论了
Reply
fleurer on #
喜欢这种写法。似乎在minix的源码里见过这种风格
Reply
Dante on #
哈哈,同好~
Reply
雨忆 on #
可以用jump table 来代替switch吧。
table driven 法?
Reply
Dante on #
咱俩其实一个意思,呵呵~
Reply
Nona Mills on #
喜欢这种写法。似乎在minix的源码里见过这种风格
Reply
Barbara Chavez on #
这是我用这个方法写的统计时间段的函数: string get_maptime(int time_ms) { struct { int iTime; string strTimeKey; }arr_times[]={ {5,"[0,5]"}, {10,"(5,10]"}, {50,"(10,50]"}, {100,"(50,100]"}, {200,"(100,200]"}, {500,"(200,500]"}, {1000,"(500,1000]"}, {-1,"(1000,~)"}, }; int count = sizeof(arr_times) / sizeof(arr_times[0]); for (int i = 0; i < count; i++) { if (arr_times[i].iTime == -1 || time_ms <= arr_times[i].iTime) { return arr_times[i].strTimeKey; } } return "(1000,~)";//实际上到不了这一步 }
Reply
Keisha Carver on #
看来有必要好好读一下。。一直放在硬盘里。。
Reply
刺猬 on #
这个实例比较简单,如果有很多case的话用表驱动法更清晰一些。
不过对于只有几种情况的case,if-else我觉得更清晰
Reply
Dante on #
哈哈,同感!~
Reply
zap on #
if或者switch的方法虽然代码比较繁琐,但是执行效率和代码体积都有优势,对嵌入式c来说,这个是更关键的。
Reply
李立强 on #
其实可以这样
char *print[] = {"this is one", "this is two", "this is three"}
return print[val-1]; //或者加一项空串,然后就不用减去1了
Reply
Dante on #
呃。。不是想实现数组。。只是文中的例子数字恰好是连续的。。
Reply
李立强 on #
那就做个转移表啊,用一个函数来返回下标,虽然效果差不多的但是看代码就爽多了,这两个方法我都是从《C和指针》中学的
Reply
null on #
struct
{
int key;
string strdata;
}arr_datas[]={
{1,"this is one"},
{2,"this is two"},
{3,"this is three"},
};
if (val>0 && val<4)
return arr_datas[val].strdata;
这样不是省去了for循环了.
Reply
arthur on #
如果传入的所以不是简单的自然数,可不是随便比较一下的问题。
如果
typedef enum{
S_A = 178 <<16 | 1,
S_B = 178 << 16 | 2
....
S_C= 192 << 16 | 1,
S_D = 192 << 16 |2,
...
}e_idx;
void get _value(e_idx idx)
{
if (idx == S_A)
printf(...);
else if (...)
}
试问,有简单的方法吗?加入enum有好几百,这个if就要好几百,可见用if会疯掉,用case可能更好,但是用table好解决吗? 呵呵
Reply
endle on #
为啥我觉得 switch 搭配 define 和 enum 更简洁?
Reply
sarrow104 on #
其实“表驱动”只不过是“数据驱动”的前奏。
这是把逻辑用数据来表现的需求。
内嵌的脚步语言,也属于“表驱动”。一点小见解。
Reply