zoukankan      html  css  js  c++  java
  • LINQ中的陷阱--TakeWhile&SkipWhile

    在用TakeWhile,SkipWhile设置陷阱之前,我们先来看一看他们的兄弟Take和Skip:

    public static IEnumerable<T> Take<T>(IEnumerable<T> source, int count)

    public static IEnumerable<T> Skip<T>(IEnumerable<T> source, int count)

     这两个操作符从字面上看就能理解其含义.Take将枚举出source中的前count个元素,返回给客户端.而Skip 则恰好相反,将跳过source中的前count个元素,枚举其余元素.LINQ内部实现代码十分简单,不用多分析.不过,他们的兄弟TakeWhile 和SkipWhile确埋下了个陷阱,让我小小的摔了一跤.现在,我就来重新布置这个陷阱: 

    考虑如下的数据源:

    static List<Customer> customers = new List<Customer> {
    new Customer { CustomerID=1,Name="woody1"},
    new Customer { CustomerID=2,Name="woody2"},
    new Customer { CustomerID=3,Name="woody3"},
    new Customer { CustomerID=4,Name="woody1"}
    };

     在这个数据源的基础上,我进行了如下操作:

    var cs1 = customers.TakeWhile(c => c.Name == "woody1");
    var cs2 = customers.TakeWhile(c => c.Name == "woody2");
    var cs3 = customers.SkipWhile(c => c.Name == "woody1");
    var cs4 = customers.SkipWhile(c => c.Name == "woody2");

    好了.现在,你能猜得出来cs1--cs4这四个IEnumerable<Customer>变量中都保存着些什么什么元素吗? 
      正确答案是: 
      cs1 : woody1(CustomerID=1) 
      cs2 : 没有任何元素 
      cs3 : woody2 , woody3 , woody1(CustomerID=4) 
      cs4 : woody1(CustomerID=1),woody2,woody3,woody1(CustomerID=4) 
      Surprise?:)反正我是小小的"惊喜"了一下.OK.研究实现代码吧... 
      TakeWhile在LINQ中实现的思想是:对数据源进行枚举,从第一个枚举得到的元素开始,调用客户端传入的predicate( c.Name == ""woodyN"),如果这个predicate委托返回true的话,则将该元素作为Current元素返回给客户端,并且,继续进行相同的枚举,判断操作.但是,一旦predicate返回false的话,MoveNext()方法将会返回false,枚举就此打住,忽略剩下的所有元素
    类似的,SkipWhile也对数据源进行枚举,从第一个枚举得到的元素开始,调用客户端的predicate,如果返回true,则跳过该元素,继续进行枚举操作.但是,如果一旦predicate返回为false,则该元素以后的所有元素,都不会再调用predicate,而全部枚举给客户端. 

    这两个方法总结为:遍历时,检查predicate条件,只要一遇到返回false,就打住,后面的元素不再去检测,直接返回结果。
      (内部实现代码很简单,不再列出) 
      现在,再回头看看陷阱的正确答案,是不是跑出来了呢?:)最开始,我一直以为是LINQ的一个BUG,还打算上LINQ论坛报BUG,不过,后来细想 Take,Skip,再详细阅读了LINQ的文档后,发现似乎这并不是BUG,这就是这两个操作符的正确逻辑.不过,起这样的名字,出这样的结果,实在让人觉得困惑啊~

    完整的控制台程序代码如下:

    class Customer
        {
            public int CustomerID { get; set; }
            public string Name { get; set; }
        }
    
    class Program
        {
            static void Main(string[] args)
            {
                List<Customer> customers = new List<Customer> {
                    new Customer { CustomerID=1,Name="woody1"},
                    new Customer { CustomerID=2,Name="woody2"},
                    new Customer { CustomerID=3,Name="woody3"},
                    new Customer { CustomerID=4,Name="woody1"}
                };      
          
                var cs1 = customers.TakeWhile(c => c.Name == "woody1");
                var cs2 = customers.TakeWhile(c => c.Name == "woody2");
                var cs3 = customers.SkipWhile(c => c.Name == "woody1");
                var cs4 = customers.SkipWhile(c => c.Name == "woody2");
    
                Console.WriteLine("Result One:TakeWhile(c => c.Name == woody1)");
                foreach (var customer in cs1)
                {
                    Console.WriteLine(customer.CustomerID + ":" + customer.Name);
                }
                Console.WriteLine("Result Two:TakeWhile(c => c.Name == woody2)");
                foreach (var customer in cs2)
                {
                    Console.WriteLine(customer.CustomerID + ":" + customer.Name);
                }
                Console.WriteLine("Result Three:SkipWhile(c => c.Name == woody1)");
                foreach (var customer in cs3)
                {
                    Console.WriteLine(customer.CustomerID + ":" + customer.Name);
                }
                Console.WriteLine("Result Four:SkipWhile(c => c.Name == woody2)");
                foreach (var customer in cs4)
                {
                    Console.WriteLine(customer.CustomerID + ":" + customer.Name);
                }
                Console.ReadKey();
    
            }
  • 相关阅读:
    LeetCode OJ 107. Binary Tree Level Order Traversal II
    LeetCode OJ 116. Populating Next Right Pointers in Each Node
    LeetCode OJ 108. Convert Sorted Array to Binary Search Tree
    LeetCode OJ 105. Construct Binary Tree from Preorder and Inorder Traversal
    LeetCode OJ 98. Validate Binary Search Tree
    老程序员解Bug的通用套路
    转载 四年努力,梦归阿里,和大家聊聊成长感悟
    转载面试感悟----一名3年工作经验的程序员应该具备的技能
    Web Service和Servlet的区别
    关于spring xml文件中的xmlns,xsi:schemaLocation
  • 原文地址:https://www.cnblogs.com/purplefox2008/p/4934426.html
Copyright © 2011-2022 走看看