不要为了面向对象而面向对象,为了lambda而lambda。以统计单词数量为例

 

本来已经把电脑合上,准备洗洗睡了,无意间在博客园的候选博客列表中发现了这么一篇博客。

标题:统计单词数量并按个数多少降序排列

地址:http://www.cnblogs.com/huaxiaoyao/archive/2010/12/19/1910381.html

 

着实让我蛋疼了一回,沉不出气,上来说两句。

 

原文引用:

 

记得年初刚来上海的时候,有一次面试时遇到一道题,是读取一个文本文件里的英文单词,要算出来每个单词的个数并降序排列,当时我的思路是循环每一个字符并判断来查找单词,然后使用dictionary<string,count>来进行保存,并使用linq排序。现在想来.,重新写一下,没有写读取文件部分。感觉当时的思路没有充分发挥.net2.0的优势。而且当时写的代码没有面对对象的感觉。

当时的代码大概是这样的,但当时没有用正则。

 

 
  
1 protected void CountWords( string text)
2 {
3 Dictionary < string , int > dict = new Dictionary < string , int > ();
4 string [] words = System.Text.RegularExpressions.Regex.Split(text, @" \W+ " );
5 foreach ( string word in words)
6 {
7 if (dict.ContainsKey(word.ToLower()))
8 {
9 dict[word.ToLower()] ++ ;
10 }
11 else
12 {
13 dict.Add(word.ToLower(), 1 );
14 }
15 }
16 // 按词频高低顺序排列
17   var items = from w in dict
18 orderby w.Value ascending
19 select w;
20 StringBuilder sb = new StringBuilder();
21
22 foreach (var w in items)
23 {
24 sb.AppendFormat( " {0}:{1}\r\n " , w.Key, w.Value);
25 }
26
27 MessageBox.Show(sb.ToString());
28 }

 

 

 

 现在又把代码写成这样:

 

 
  
1 // 存储单词的数量 和 单词的内容
2   struct myword
3 {
4 public string word { get ; set ; }
5 public int count { get ; set ; }
6
7 public override string ToString()
8 {
9 return string .Format( " {0}:{1} " , word, count);
10 }
11 }
12
13 // 计算单词个数
14   protected void countWords( string content)
15 {
16 List < myword > wordlist = new List < myword > ();
17 MatchCollection mc = Regex.Matches(content, @" [a-zA-Z]+\b " );
18 foreach (Match m in mc)
19 {
20 myword word = wordlist.Find((w) =>
21 {
22 return w.word.ToLower() == m.Value.ToLower();
23 });
24 if (word.count == 0 ) // 如果是初次添加
25   {
26 wordlist.Add( new myword { word = m.Value, count = 1 });
27 }
28 else
29 {
30 wordlist.Remove(word);
31 wordlist.Add( new myword { word = m.Value, count = word.count + 1 });
32 }
33 }
34 // 按count由高到低排序
35   wordlist.Sort(
36 (x, y) =>
37 {
38 return y.count.CompareTo(x.count);
39 }
40 );
41 wordlist.ForEach( w => Console.WriteLine(w) );
42 }

 

 

各位看官,如果仔细看一定就会发现问题的所在了。

统计单词个数,本来就是个小功能。只要在单词引用数上+1就行了。

为了看起来更加面向对象,原文作者,写了个myword类,

而后用了大量lambda表达式! 

 

我对这位作者佩服的五体投地!

蛋疼,上面的代码效率起码是下面的3倍以上,如果重复的单词少,文章内容长的话,慢10倍都很正常。

上面的代码,扣去正则执行时间,运算量是o(n), n代码单词个数,

而下面的代码,运算深度为o((1+2+3+...+n)*n)

还不包括每次都傻不垃圾的new myword, List的Add,Remove运算操作,

算上gc1,gc2深度的垃圾回收时间,楼主很强大!

 

直接用word.count++不就行了。

另外楼主貌似不知道,在key,value检索下,Dictionary是o(1)计算深度,

而List的Find是由c#提供的lambda表达式,实际就是遍历一遍List对象,效率也是o(n), 

此处的ni为已找到的单词个数,再乘以总个数n, 就可以算出来运算量为 o ( ( 1 + 2 + 3 + ... + n ) * n )

为了面向对象而面向对象,还很自我感觉良好的用了lambda表达式,

 

而且从我本人一向偏好的省代码角度出发◎,下面的代码要比上面还多14行!

虽说在现在流程配置的电脑上,这两段代码在效率上的优势差距并不明显,

但是如此般的改进,我不知道是作者搬门弄武,显摆对c#的水平有多高,

还是作者对c#越来越不了解了?

 

写这种技术类文章也不怕被人骂的,真是摊糟水摊到家了!

 

我的改进方法:将List类还是改用Dictionary, Lambda表达式还可以用。

下面的 new myword(); add(new myword()); remove(word); 去掉;

直接word.count++;来的痛快!

 

不好意思,刚才review了一遍原文,发现:

“ 当时的代码大概是这样的,但当时没有用正则。 ”

又发现了如下的代码:

 
  
string [] words = System.Text.RegularExpressions.Regex.Split(text, @" \W+ " );

 

 

我现在开始简直怀疑原文作者到底是中文表达能力不好?,还是根本不懂正则表示式是什么!

 

\W+ 不是显摆着就是正则表达式嘛~~

 

我又着实被雷到了!!

 

又发现新问题了:

struct myword 的申明中:

 
  
1 public override string ToString()
2 {
3 return string .Format( " {0}:{1} " , word, count);
4 }

 

虽然说结构的基类也是Object,但是结构就要像结构的用法去用!

因为结构实际上是一种值类型。

 

引用:http://www.cnblogs.com/yzxchoice/archive/2007/05/14/745491.html

结构是值类型:值类型在堆栈上分配地址,所有的基类型都是结构类型,例如:int 对应System.int32 结构,string 对应 system.string 结构 ,通过使用结构可以创建更多的值类型

  类是引用类型:引用类型在堆上分配地址

  堆栈的执行效率要比堆的执行效率高

 

作为值类型,结构变量的创建一般不用 new 进行,就像 c# 中的 int 类型一样,直接 myword.word = ""; myword.count=1; 即可。

各位可以尝试以下代码:

1. int x = new int(1);

2. int y = 1;

然后在Expression Watch中查看 变量 x, y 。

前者现实类型为 Object(int)

后者类型为原生值类型 int

 

换成myword

也应该是:new 出来的为 Object(myword) ; 而 直接赋值的 为 原生 myword 结构。

 

虽然到目前为止我还不清楚这两者的区别,

但是在Java中,int x = 1 ; 和 Integer y = new Integer(1) ; 是存在本质区别的。

一个是原生的值类型,另外一个是 value package Object,就是数据包装类型。是类的实例,即对象!

 

两者在JIL上的执行效率可谓相差甚大!,但是我不知道在.net中 new int()  跟 int x = 1 的效率相差有多大!

因为.net的外表太华丽了,把所有的细节都隐藏在背后,要知道 int 类型执行之所以同样具有 int.Parase();

int.ToString() 方法,都是因为.net封装的好,把ValueTypeObject跟正常的Object封装的一模一样,天衣无缝!

 

但是对于new出来的 Object(int) 跟 int 类型的区别,我就不是很清楚了。

 

 

转载于:https://www.cnblogs.com/gongji/archive/2010/12/20/1910972.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值