zoukankan      html  css  js  c++  java
  • Functional Programming&Lazy Code:被我忘记的迭代器

    本文给出一个Functional Programming和Lazy Code的一个例子。跟着思路走,关键的地方会有相应的说明。

    我们想实现一个判断"素数"的小程序,如下:

    using System;
    
    namespace FunctionalProgramming
    {
        class Program
        {
            static void Main(string[] args)
            {
                var number = int.Parse(Console.ReadLine());
    
                var result = true;
    
                for(long i=2;i<number;i++)
                {
                    if(number%i==0)
                    {
                        result = false;
                        break;
                    }
                }
                Console.WriteLine(result);
            }
        }
    }

    上面的代码虽能完成功能,但不够整洁。不是我们想要的代码。
    我们提取其中的方法,重新实现如下:

    using System;
    
    namespace RefactorExample
    {
        class Program
        {
            static void Main(string[] args)
            {
                var number = int.Parse(Console.ReadLine());
    
                var result =  IsPrime(number);;
                Console.WriteLine(result);
            }
            //Refactor
            private static bool IsPrime(int number)
            {
                var result=true;
                for (long i = 2; i < number; i++)
                {
                    if (number%i == 0)
                    {
                        result = false;
                        break;
                    }
                }
                return result;
            }
        }
    }

    以此为基础,借助扩展方法,针对一个数组,我们可以方便的改写上面的代码如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace AHigherCalling
    {
        static class Program
        {
            static void Main(string[] args)
            {
                var number = new [] {3,5,7,9,11,13};
    
                foreach (var prime in number.Find(IsPrime).Take(2))
                {
                    Console.WriteLine(prime);
                }
                Console.ReadKey();
            }
    
            
            private static IEnumerable<int> Find(this IEnumerable<int> values,Func<int,bool> test )
            {
                var result = new List<int>();
                foreach (var value in values)
                {
                    if (test(value))
                        result.Add(value);
                }
                return result;
            }
    
            private static bool IsPrime(int value)
            {
                var result = true;
                for (long i = 2; i < value; i++)
                {
                    if (value % i == 0)
                    {
                        result = false;
                        break;
                    }
                }
                return result;
            }
    
            //一些其他的类似IsPrime的方法
            private static bool IsEven(int value)
            {
                return value%2 == 0;
            }
            private static bool IsOdd(int value)
            {
                return value%2 != 0;
            }
        }
    }

    这样做的目的是提供更清洁的语法,并提高程序应对变化的能力。例如,我们实现的两个类似IsPrime方法。

    单看Find方法。貌似没有什么问题,当然我们可以用ReShaper生成LINQ语句,替换掉那个for循环。

    View Code
    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace AHigherCalling
    {
        static class Program
        {
            static void Main(string[] args)
            {
                var number = new [] {3,5,7,9,11,13};
    
                foreach (var prime in number.Find(IsPrime).Take(2))
                {
                    Console.WriteLine(prime);
                }
                Console.ReadKey();
            }
    
            
            private static IEnumerable<int> Find(this IEnumerable<int> values,Func<int,bool> test )
            {
                //LINQ替换掉了for循环
                return values.Where(value => test(value)).ToList();
            }
    
            private static bool IsPrime(int value)
            {
                var result = true;
                for (long i = 2; i < value; i++)
                {
                    if (value % i == 0)
                    {
                        result = false;
                        break;
                    }
                }
                return result;
            }
    
            //一些其他的类似IsPrime的方法
            private static bool IsEven(int value)
            {
                return value%2 == 0;
            }
            private static bool IsOdd(int value)
            {
                return value%2 != 0;
            }
        }
    }

    程序正常运行。
    貌似我们的程序没有什么问题了,那是因为我们这个数组不够大!我们把numbers变的很大!如下:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    
    namespace AHigherCalling
    {
        static class Program
        {
            static void Main(string[] args)
            {
                foreach (var prime in GetRandomNumbers().Find(IsPrime).Take(2))
                {
                    Console.WriteLine(prime);
                }
                Console.ReadKey();
            }
    
            private static IEnumerable<int> GetRandomNumbers()
            {
                //yield return 3;
                //yield return 5;
                //yield return 7;
                //yield return 9;
                //yield return 11;
                //yield return 13;
                Random random = new Random();
                while (true)
                {
                    yield return random.Next(90000, 100000);
                }
            }
            
            private static IEnumerable<int> Find(this IEnumerable<int> values,Func<int,bool> test )
            {
                //LINQ替换掉了for循环
                return values.Where(value => test(value)).ToList();
            }
    
            private static bool IsPrime(int value)
            {
                var result = true;
                for (long i = 2; i < value; i++)
                {
    
                    if (value % i == 0)
                    {
                        result = false;
                        break;
                    }
                }
                return result;
            }
    
            //一些其他的类似IsPrime的方法
            private static bool IsEven(int value)
            {
                return value%2 == 0;
            }
            private static bool IsOdd(int value)
            {
                return value%2 != 0;
            }
        }
    }

    程序就也陷入死循环了!而我这次想获取的只是其前2个而已。
    问题出在哪里?

    不难发现,当然在Find这里!

    还记得前面我实现的Find方法吗?如下:

            private static IEnumerable<int> Find(this IEnumerable<int> values,Func<int,bool> test )
            {
                var result = new List<int>();
                foreach (var value in values)
                {
                    if (test(value))
                        result.Add(value);
                }
                return result;
            }

    使用ReShaper重构过如下:

            private static IEnumerable<int> Find(this IEnumerable<int> values,Func<int,bool> test )
            {
                //LINQ替换掉了for循环
                return values.Where(value => test(value)).ToList();
            }

    简单分析问题所在后,可以想到的解决方法,如下:

    使用迭代器:

            private static IEnumerable<int> Find(this IEnumerable<int> values,Func<int,bool> test )
            {
                foreach (var value in values)
                {
                    if (test(value))
                        yield return value;
                }
            }

    或是:

            private static IEnumerable<int> Find(this IEnumerable<int> values,Func<int,bool> test )
            {
                return values.Where(value => test(value));
            }

    这样程序就按我既定的想法运行了。

    从ReShaper生成的代码来看,问题出在立即执行的ToList()那里!但毕竟ReShaper只是个工具,其翻译的是我们的代码,不推卸责任的说,问题出在我们,因为使用迭代器更正后,ReShaper不也生成了正确的代码了么?

    update:

    from: http://stackoverflow.com/questions/7062882/searching-a-tree-using-linq

  • 相关阅读:
    SSM后台管理开发日志(三)
    文件权限
    adb详细教学
    adb基础命令001
    SQL训练题库002(建议copy到sqlserver里实战练习,多做一下)
    SQL增删改查,列的更改,更改列名表名,运算符连接符,注释
    SQL增加约束
    SQL 建表、删表和数据,增删约束
    The firstday i join in cnblogs..."Hello everyone"...
    C#日期时间格式化
  • 原文地址:https://www.cnblogs.com/DebugLZQ/p/2984564.html
Copyright © 2011-2022 走看看