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

  • 相关阅读:
    POJ 3126 Prime Path
    POJ 2429 GCD & LCM Inverse
    POJ 2395 Out of Hay
    【Codeforces 105D】 Bag of mice
    【POJ 3071】 Football
    【POJ 2096】 Collecting Bugs
    【CQOI 2009】 余数之和
    【Codeforces 258E】 Devu and Flowers
    【SDOI 2010】 古代猪文
    【BZOJ 2982】 combination
  • 原文地址:https://www.cnblogs.com/DebugLZQ/p/2984564.html
Copyright © 2011-2022 走看看