一:背景

昨天在看C#函数式编程这本书的时候,有一处让我干着急,需求是这样:给多行文字加上数字列表项。

针对这个需求你会如何快捷高效的给每个项目加上数字编号呢?我看书中是这样实现的,如下代码


   public class Program
   {

       public static void Main(string[] args)
       
{
           var list = new List<string>()
           {
               "cnblogs","csdn","zhihu","oschina"
           };

           var items = list.Zip(Enumerable.Range(1, list.Count + 1), (item, i) => $"{i}. {item}").ToList();

           items.ForEach(Console.WriteLine);
       }
   }

------------------- output -------------------
1. cnblogs
2. csdn
3. zhihu
4. oschina
Press any key to continue . . .

怎么说呢,需求能实现没有问题,但这里还是累赘了,因使用到了拉链函数Zip 和生成范围的Range,全纠缠到一块,有没有更简单粗暴的方式呢?其实你只用Select的一个带迭代变量的重载方法就可以搞定,但现实中还是有很多的程序员不会使用或者说不知道,所以优化后的代码如下。


var items = list.Select((item, i) => $"{i + 1}. {item}").ToList();

------------------- output -------------------
1. cnblogs
2. csdn
3. zhihu
4. oschina
Press any key to continue . . .

二:源码探究

相信编码多年的我们无数次的在憎恨foreach没有带上索引,这么普罗大众的需求尽然都没有实现,而python这样的语言早就给实现了,为了解决这个不足,我还得需要单独定义一个变量在迭代时即时记录,烦不胜烦,就像下面这样。

            var index = 0;

           foreach (var item in list)
           {
               index++;
               Console.WriteLine(item);
           }

可能FCL类库程序员也深有体会,所以加了一个可以在迭代中获取当前index的绝妙方法,这么造福人类的方法却发现身边知道的人少之又少,小遗憾哈。

1. ILSpy查看源码

从下面代码的 SelectIterator 枚举类可以看到,其实在底层也是单独给你定义了一个index,然后逐一回调给你的回调函数,这种封装很有必要,不过全是高阶函数,功底很深哈!

public static IEnumerable<TResult> Select<TSource, TResult>(this IEnumerable<TSource> source, Func<TSource, int, TResult> selector)
{
   if (source == null)
   {
       throw Error.ArgumentNull("source");
   }
   if (selector == null)
   {
       throw Error.ArgumentNull("selector");
   }
   return SelectIterator(source, selector);
}

private static IEnumerable<TResult> SelectIterator<TSource, TResult>(IEnumerable<TSource> source, Func<TSource, int, TResult> selector)
{
   int index = -1;
   foreach (TSource item in source)
   {
       index = checked(index + 1);
       yield return selector(item, index);
   }
}

三:其他案例

其实有太多例子需要使用迭代器中的index值了,比如最近业务中要计算各个月份的环比率,用今天讲到的这个方法就可以非常完美的解决,简化后的代码如下。


       public static void Main(string[] args)
       
{
           var list = new List<int>()
           {
               10, 20, 30,40,50, 60,70,80,90,100,110,120,
           };

           var rateList = list.Select((item, index) =>
           {
               return index == 0 ? 0 : Math.Round(((decimal)list[index] - list[index - 1]) / list[index - 1], 2);
           }).ToList();

           rateList.ForEach(Console.WriteLine);
       }

------------------- output -------------------
0
1
0.5
0.33
0.25
0.2
0.17
0.14
0.12
0.11
0.1
0.09
Press any key to continue . . .

好了,本篇来自于触景生情,希望您编码有帮助。


©著作权归作者所有:来自51CTO博客作者mb5fd86a704dffe的原创作品,如需转载,请注明出处,否则将追究法律责任

更多相关文章

  1. 当模板方法遇到了委托函数,你的代码又可以精简了
  2. awk函数-摘自Linux Shell核心编程指南
  3. C++入门
  4. 剩余参数与参数引用及回调函数:array_map(), array_filter,array_
  5. 第6章 0201-常用字符串函数介绍,学习心得、笔记(PHP常用字符串函数
  6. 【每日一练】PMP项目管理专业资格认证考试练习题(五十二)
  7. 0201-常用字符串函数
  8. 0129-数组的排序, 数组的合并, 数组成员的统计
  9. 第5章 0129-细说常用的数组函数,学习心得、笔记(数组的排序, 数组

随机推荐

  1. 使用ng-repeat-start和ng-repeat-end与嵌
  2. JavaScript中的数学对象中的方法
  3. 用于Internet Explorer的javaScript中的i
  4. BootStrap3.0学习--JavaScript 插件
  5. 关于洗牌算法的错误认识
  6. Javascript知识汇总------面向对象中继承
  7. 在关联数组中移动元素[重复]
  8. 对JavaScript优化及规范的一些感想
  9. 键盘出现时,UIWebView滚动。导致点击偏移
  10. 我如何捕获并插入Meteor.Error警报从Mete