.NET Lambda表达式的函数式特性:索引示例
创始人
2024-04-27 03:31:27
0

.NET Lambda表达式最节省的部分

使用Lambda表达式还可以节省许多代码(相信您从第一个示例中也可以看出来了)。不过我认为,最省代码的部分更应该可能是其“分组”和“字典转化”等功能。因此,我们来看下一个示例。

这个示例可能更加贴近现实。不知您是否关注过某些书籍后面的“索引”,它其实就是“列出所有的关键字,根据其首字母进行分组,并且要求对每组内部的关键字进行排序”。简单说来,我们需要的其实是这么一个方法:

  1. static Dictionary< char, List< string>> GetIndex(IEnumerable< string> keywords) { ... }  

想想看,您会怎么做?其实不难(作为示例,我们这里只关注小写英文,也不关心重复关键字这种特殊情况):

  1. static Dictionary< char, List< string>> GetIndex(IEnumerable< string> keywords)  
  2. {  
  3.     // 定义字典  
  4.     var result = new Dictionary< char, List< string>>();  
  5.  
  6.     // 填充字典  
  7.     foreach (var kw in keywords)  
  8.     {  
  9.         var firstChar = kw[0];  
  10.         List< string> groupKeywords;  
  11.  
  12.         if (!result.TryGetValue(firstChar, out groupKeywords))  
  13.         {  
  14.             groupKeywords = new List< string>();  
  15.             result.Add(firstChar, groupKeywords);  
  16.         }  
  17.  
  18.         groupKeywords.Add(kw);  
  19.     }  
  20.  
  21.     // 为每个分组排序  
  22.     foreach (var groupKeywords in result.Values)  
  23.     {  
  24.         groupKeywords.Sort();  
  25.     }  
  26.  
  27.     return result;  
  28. }  
  29.  

那么如果利用Lambda表达式及.NET框架中定义的扩展方法,代码又会变成什么样呢?请看:

  1. static Dictionary< char, List< string>> GetIndexByLambda(IEnumerable< string> keywords)  
  2. {  
  3.     return keywords  
  4.         .GroupBy(k => k[0]) // 按照首字母分组  
  5.         .ToDictionary( // 构造字典  
  6.             g => g.Key, // 以每组的Key作为键  
  7.             g => g.OrderBy(k => k).ToList()); // 对每组排序并生成列表  
  8. }  

光从代码数量上来看,前者便是后者的好几倍。而有关“声明式”,“what”等可读性方面的优势就不再重复了,个人认为它比上一个例子给人的“震撼”有过之而无不及。

试想,如果我们把GetIndexByLambda方法中的Lambda表达式改成.NET 2.0中delegate形式的写法:

  1. static Dictionary< char, List< string>> GetIndexByDelegate(IEnumerable< string> keywords)  
  2. {  
  3.     return keywords  
  4.         .GroupBy(delegate(string k) { return k[0]; })  
  5.         .ToDictionary(  
  6.             delegate(IGrouping< charstring> g) { return g.Key; },  
  7.             delegate(IGrouping< charstring> g)  
  8.             {  
  9.                 return g.OrderBy(delegate(string s) { return s; }).ToList();  
  10.             });  
  11. }  

您愿意编写这样的代码吗?

.NET Lambda表达式体现了函数式编程特性

因此,Lambda表达式在这里还是起着决定性的作用。事实上正是因为有了Lambda表达式,.NET中的一些函数式编程特性才被真正推广开来。“语言特性”决定“编程方式”的确非常有道理。这一点上Java是一个很好的反例:从理论上说,Java也有“内联”的写法,但是C#的使用快感在Java那边还只能是个梦。试想GetIndexByLambda在Java中会是什么情况3:

  1. public Dictionary< Char, List< String>> GetIndexInJava(Enumerable< String> keywords)  
  2. {  
  3.     return keywords  
  4.         .GroupBy(  
  5.             new Func< String, Char> {  
  6.                 public Char execute(String s) { return s.charAt(0); }  
  7.             })  
  8.         .ToDictionary(  
  9.             new Func< Grouping< Char, String>, Char> {  
  10.                 public Char execute(IGrouping< Char, String> g) { return g.getKey(); }  
  11.             },  
  12.             new Func< Grouping< Char, String>, List< string>> {  
  13.                 public List< String> execute(IGrouping< Char, String> g)  
  14.                 {  
  15.                     return g  
  16.                         .OrderBy(  
  17.                             new Func< String, String> {  
  18.                                 public String execute(String s) { return s; }  
  19.                             })  
  20.                         .ToList();  
  21.                 }  
  22.             });  
  23. }  

一股语法噪音的气息扑面而来,让人无法抵挡。由于Java中的匿名类型语法(即上面这种内联写法)连类型信息(new Func< String, Char>{ ... }这样的代码)都无法省去,因此给人非常繁琐的感觉。面对这样的代码,您可能会有和我一样的想法:“还不如最普通的写法氨。没错,这种函数式编程的风格,由于缺乏语言特性支持,实在不适合在Java语言中使用。事实上,这种内联写法很早就出现了(至少在02、03年我还在使用Java的时候就已经有了),但是那么多年下来一点改进都没有。而Lambda表达式出现之后,社区中立即跟进了大量项目,如Moq,Fluent NHibernate等等,充分运用了C# 3.0的这一新特性。难道这还不够说明问题吗?

对了,再次推荐一下Scala语言,它的代码可以写的和C#一样漂亮。我不是Java平台的粉丝,更是Java语言的忠实反对者,但是我对Java平台上的Scala语言和开源项目都抱有强烈的好感。

既然谈到了函数式编程,那么就顺便再多说几句。其实这两个例子都有浓厚的函数式编程影子在里面,例如,对于函数试编程来说,Where常被叫做filter,Select常被叫做map。而.NET 3.5中定义的另一些方法在函数式编程里都有体现(如Aggregate相当于fold)。如果您对这方面感兴趣,可以关注Matthew Poswysocki提出的Functional C#类库。

以上就介绍了.NET Lambda表达式的另一个范例。

【编辑推荐】

  1. .NET Lambda表达式的语义:字符串列表范例
  2. 使用.NET 3.5 Lambda表达式实现委托
  3. 各版本.NET委托的写法回顾
  4. C# Actor模型开发实例:网络爬虫
  5. 强类型和Actor:ActorLite的演示

相关内容

热门资讯

如何允许远程连接到MySQL数... [[277004]]【51CTO.com快译】默认情况下,MySQL服务器仅侦听来自localhos...
如何利用交换机和端口设置来管理... 在网络管理中,总是有些人让管理员头疼。下面我们就将介绍一下一个网管员利用交换机以及端口设置等来进行D...
施耐德电气数据中心整体解决方案... 近日,全球能效管理专家施耐德电气正式启动大型体验活动“能效中国行——2012卡车巡展”,作为该活动的...
Windows恶意软件20年“... 在Windows的早期年代,病毒游走于系统之间,偶尔删除文件(但被删除的文件几乎都是可恢复的),并弹...
20个非常棒的扁平设计免费资源 Apple设备的平面图标PSD免费平板UI 平板UI套件24平图标Freen平板UI套件PSD径向平...
德国电信门户网站可实时显示全球... 德国电信周三推出一个门户网站,直观地实时提供其安装在全球各地的传感器网络检测到的网络攻击状况。该网站...
着眼MAC地址,解救无法享受D... 在安装了DHCP服务器的局域网环境中,每一台工作站在上网之前,都要先从DHCP服务器那里享受到地址动...
为啥国人偏爱 Mybatis,... 关于 SQL 和 ORM 的争论,永远都不会终止,我也一直在思考这个问题。昨天又跟群里的小伙伴进行...