• 《C#本质论》读书笔记(14)支持标准查询操作符的集合接口



     


    14.2.集合初始化器

    使用集合初始化器,程序员可以采用和数组相似的方式,在集合的实例化期间用一套初始的成员来构造这个集合。
    如果没有集合初始化器,就只有在集合实例化后才能显示添加到集合中——例如使用 System.Collections.Generic.ICollection<T>Add( )方法。

    1. static void Main(string[] args)    
    2. {    
    3.     List<string> sevenWorldBlunders;    
    4.     sevenWorldBlunders = new List<string>()    
    5.     {    
    6.         "Wealth without work",    
    7.         "Pleasure without conscience",    
    8.        "Knowledge without character",    
    9.        "Commerce without morality",    
    10.        "Science without humanity",    
    11.        "Worship without sacrifice",    
    12.        "Politics without principle"    
    13.     };    
    14.     Print(sevenWorldBlunders);    
    15.     Console.Read();    
    16. }    
    17. private static void Print<T>(IEnumerable<T> items)    
    18. {    
    19.     foreach (T item in items)    
    20.     {    
    21.         Console.WriteLine(item);    
    22.     }    
    23. }    


     

    集合初始化器,基本条件


           应该实现 System.Collections.Generic.ICollection<T> 接口,就可以保证集合支持一个Add()方法,这个需求还有一个较为宽松的版本,只要求实现 IEnumerable<T>的类型上存在一个或多个Add()方法。
    之所以允许不支持 ICollections<T> 的集合使用初始化器,原因有两个。

    1.大多数集合(实现了  IEnumerable<T> 的类型)都没有实现 ICollections<T> ,这使得集合初始化器用处不大。
    2.由于要匹配方法名,签名要和初始化兼容,所以可以在集合中初始化更加多样化的数据项。
    例如,new DataStore(){a,{b,c}} —— 只要一个Add()方法的签名兼容于a,另一个Add()方法兼容b,c。

    匿名类型集合初始化器


    匿名类型不能使用集合初始化器。因为集合初始化器要求执行一次构造器的调用,但是你根本没有办法命名这个构造器。

    解决方法1

    是定义一个下面的方法:

    1. static List<T> CreateList<T>(T t)  
    2. {  
    3.     return new List<T>();  
    4. }  


    解决方法2

    使用数组初始化器。由于不能在构造器中指定数据类型,所以允许使用 new[ ] ,从而为匿名数组初始化器使用数组初始化语法。

    1. static void Main(string[] args)    
    2.  {    
    3.      var worldCup2006Finalists = new[]{    
    4.          new{    
    5.              TeamName = "France",    
    6.              Players = new string[]{    
    7.                  "Fabien Barthez","Gregory Coupet",    
    8.                  "Mickael Landreau","Eric Abidal"    
    9.              }    
    10.          },    
    11.          new{    
    12.              TeamName = "Italy",    
    13.              Players = new string[]{    
    14.                  "Gianlugi Buffon","Angelo Peruzzi",    
    15.                  "Marco Amelia","Cristian Zaccardo"    
    16.              }    
    17.          },     
    18.      };    
    19.      Print(worldCup2006Finalists);    
    20.      Console.ReadKey();    
    21.  }    
    22.     
    23.  private static void Print<T>(IEnumerable<T> items)    
    24.  {    
    25.      foreach (T item in items)    
    26.      {    
    27.          Console.WriteLine(item);    
    28.      }    
    29.  }    

     
     
     

    14.3.是什么使类成为一个集合:IEnumerable<T>


    14.3.2 foreach和IEnumerable<T>

           因为数组的长度固定,支持索引操作符([ ])。但并不是所有类型的集合都包含已知数量的元素。包括Stack<T>、Queue<T>以及Dictionary<Tkey, Tvalue>,都不支持索引获取元素。迭代器(iterator)模式提供这个能力。
           System.Collections.Generic.IEnumerator<T>和非泛型System.Collections.Generic.IEnumerator接口的设计允许使用迭代器模式遍历集合。
     

    IEnumerator<T>从IEnumerator派生,后者包含3各成员。

    1.bool MoveNext():从集合中一个元素移动到下一个元素,同时检测是否已经枚举完集合中的每个元素。

    2.只读属性Current:返回当前元素。

    利用这2个成员,只需要一个while循环即可遍历集合

    3.Reset()方法一般抛出Notimplemented Exception异常,永远不要调用它。


    使用while遍历集合
     
    Stack<T>

    public class Stack<T> : IEnumerable<T>, IEnumerable, ICollection, IReadOnlyCollection<T>



    前面代码忽略了CIL代码两个重要实现细节:交错和错误处理

       

    1

    状态共享


           假如同时两个循环交错遍历同一个集合(一个foreach嵌套另一个foreach),集合必须确保当前的MoveNext()能正确定位到下一个元素,问题是交错循环可能互相干扰(多线程执行循环会发生同样问题)。
            因为解决这个问题,集合类不直接支持 IEnumerator IEnumerator<T>接口。所以,用另一个接口,IEnumerable<T>,它唯一的方法就是GetEnumerator()。枚举数(enumerator)相当于一个“游标”或者“书签”。可以有多个书签,移动每个书签都可以独立于其他书签来遍历集合。

    1. Stack<int> stack = new Stack<int>();  
    2. Stack<int>.Enumerator stackEnumerator = stack.GetEnumerator();  
    3. int number;  
    4. while (stackEnumerator.MoveNext())  
    5. {  
    6.     number = stackEnumerator.Current;  
    7.     Console.WriteLine(number);  
    8. }  

       

    2

    清理状态


           由于实现 IEnumerator<T> 接口维持状态,退出循环后,有时需要对状态进行清理。为此,IEnumerator<T> 接口继承IDisposable。假如实现 IDisposable,就会调用Dispose()方法。就能在foreach循环退出之后调用Dispose()。与最终的CIL代码等价。

    1. System.Collections.Generic.Stack<int> stack = new System.Collections.Generic.Stack<int>();  
    2. Stack<int>.Enumerator stackEnumerator = stack.GetEnumerator();  
    3. IDisposable disposable;  
    4. try  
    5. {  
    6.     int number;  
    7.     while (stackEnumerator.MoveNext())  
    8.     {  
    9.         number = stackEnumerator.Current;  
    10.         Console.WriteLine(number);  
    11.     }  
    12. }  
    13. finally  
    14. {  
    15.     //显式类型转换用于IEnumerator < T >  
    16.     disposable = (IDisposable)stackEnumerator;  
    17.     disposable.Dispose();  
    18.     //IEnumerator将使用操作符,除非IDisposable支持在编译时是已知的  
    19.     disposable = (stackEnumerator as IDisposable);  
    20.     if (disposable != null)  
    21.     {  
    22.         disposable.Dispose();  
    23.     }  
    24. }  

    由于IEnumerator<T>支持IDisposable接口,可以使用using关键字简化

    1. System.Collections.Generic.Stack<int> stack = new System.Collections.Generic.Stack<int>();    
    2. int number;    
    3. using (Stack<int>.Enumerator stackEnumerator = stack.GetEnumerator())    
    4. {    
    5.     while (stackEnumerator.MoveNext())    
    6.     {    
    7.         number = stackEnumerator.Current;    
    8.         Console.WriteLine(number);    
    9.     }    
    10. }    

    14.4.标准查询操作符 

    后面的使用标准查询操作符示例类:

    Patent类和 Inventor
    1. public class Patent  
    2. {  
    3.     public string Title { getset; }  
    4.   
    5.     public string YearOfPublication { getset; }  
    6.   
    7.     public string ApplicationNumber { getset; }  
    8.   
    9.     public long[] InventorIds { getset; }  
    10.   
    11.     public override string ToString()  
    12.     {  
    13.         return string.Format("{0}({1})", Title, YearOfPublication);  
    14.     }  
    15. }  
    16.   

    17. public class Inventor  
    18. {  
    19.     public long Id{ getset; }  
    20.     public string Name { getset; }  
    21.   
    22.     public string City { getset; }  
    23.     public string State { getset; }  
    24.     public string Country { getset; }  
    25.     public override string ToString()  
    26.     {  
    27.         return string.Format("{0},({1},{2})", Name, City, State);  
    28.     }  
    29. }  


    PatentData
    1. public static class PatentData  
    2.     {  
    3.         public static readonly Inventor[] Inventors = new Inventor[]  
    4.         {  
    5.             new Inventor()  
    6.             {  
    7.                Name = "胡韩三",City ="韩国",State="SE",Country="KOR", Id =1,  
    8.             },  
    9.             new Inventor()  
    10.             {  
    11.                Name = "Michael Jackson",City ="美国",State="indiana",Country="USA", Id =2,  
    12.             },  
    13.             new Inventor()  
    14.             {  
    15.                Name = "唐三三",City ="中国",State="CQ",Country="CHN", Id =3,  
    16.             },  
    17.             new Inventor()  
    18.             {  
    19.                Name = "John Michaelis",City ="芝加哥",State="IL",Country="USA", Id =4,  
    20.             },  
    21.             new Inventor()  
    22.             {  
    23.                Name = "Mary Phelps Jacob",City ="纽约",State="NY",Country="KOR", Id =5,  
    24.             }  
    25.         };  
    26.   
    27.         public static readonly Patent[] Patents = new Patent[]  
    28.         {  
    29.             new Patent()  
    30.             {  
    31.                 Title="留声机",YearOfPublication="1877",InventorIds = new long[]{1}  
    32.             },  
    33.             new Patent()  
    34.             {  
    35.                 Title="活动电影放映机",YearOfPublication="1888",InventorIds = new long[]{1}  
    36.             },  
    37.             new Patent()  
    38.             {  
    39.                 Title="电报机",YearOfPublication="1837",InventorIds = new long[]{4}  
    40.             },  
    41.             new Patent()  
    42.             {  
    43.                 Title="飞机",YearOfPublication="1903",InventorIds = new long[]{2,3}  
    44.             },  
    45.             new Patent()  
    46.             {  
    47.                 Title="蒸汽机车",YearOfPublication="1815",InventorIds = new long[]{5}  
    48.             },  
    49.                         new Patent()  
    50.             {  
    51.                 Title="露背胸罩",YearOfPublication="1914",InventorIds = new long[]{7}  
    52.             },  
    53.         };  
    54.     }  


    输出Main()
    1. class Program  
    2. {  
    3.     static void Main(string[] args)  
    4.     {  
    5.        IEnumerable <Patent> patents = PatentData.Patents;  
    6.         Print(patents);  
    7.         Console.WriteLine();  
    8.         IEnumerable<Inventor> inventors = PatentData.Inventors;  
    9.         Print(inventors);  
    10.         Console.ReadKey();  
    11.     }  
    12.   
    13.     private static void Print<T>(IEnumerable<T> items)  
    14.     {  
    15.         foreach (T item in items)  
    16.         {  
    17.             Console.WriteLine(item);  
    18.         }  
    19.     }  
    20. }  

     

    14.4.1

    Where()筛选


    1. IEnumerable <Patent> patents = PatentData.Patents;  
    2.   //where  
    3.   patents = patents.Where(p => p.YearOfPublication.StartsWith("18"));  
    4.   Print(patents);  

    14.4.2

    Select()投射


    这里的Select()调用,并未造成输出变化。这里只是巧合
    1. IEnumerable <Patent> patents = PatentData.Patents;  
    2.  IEnumerable<Patent> patentsOf1800 =   
    3.      patents.Where(p => p.YearOfPublication.StartsWith("18"));  
    4.  IEnumerable<string> items =  
    5.      patentsOf1800.Select(p => p.ToString());  
    6.  Print(items);  


    例子2
    1. string rootDirectory = @"E:MI-O2O商城APPpsSystem";  
    2.             string serchPattern = "*.html";  
    3.             IEnumerable<string> fileList = Directory.GetFiles(rootDirectory, serchPattern);  
    4.             IEnumerable<FileInfo> files = fileList.Select(file => new FileInfo(file));  
    5.             Print(files);  

     fileList的类型是  IEnumerable<string>  ,而使用Select()投射功能可以将集合中的每一项转换成一个  System.IO.FileInfo 对象。

    例子3:匿名方法
    1. string rootDirectory = @"E:MI-O2O商城APPpsSystem";  
    2. string serchPattern = "*.html";  
    3. IEnumerable<string> fileList = Directory.GetFiles(rootDirectory, serchPattern);  
    4. var items = fileList.Select(  
    5.     file =>  
    6.     {  
    7.         FileInfo fileinfo = new FileInfo(file);  
    8.         return new  
    9.         {  
    10.             FileName = fileinfo.Name,  
    11.             Size = fileinfo.Length  
    12.         };  
    13.     }); 

    14.  
    Where():在“垂直”方向筛选集合(减少集合中项的数量)
    Select():在“水平”方向减少集合的规模(减少列的数量)

    14.4.3

    Count()计数

    1. IEnumerable<Patent> patents = PatentData.Patents  ;  
    2. Console.WriteLine("Patent Count:{0}",patents.Count());
    3. Console.WriteLine("Patent Count in 1800s:{0}",  
    4.     patents.Count(p=>p.YearOfPublication.StartsWith("18")));  


           ICollection<T>包含了Count属性,所以如果支持ICollection<T>,调用Count()方法,会对集合转型,并直接调用Count。如果不支持,Enumerable.Count()就会枚举所有项,而不是调用内建Count机制。
            如果计数的目的是看是否大于( if(patents.Count()>0){...}),那首选的做法应使用Any()操作符(if(patents.Any()){...})只尝试遍历集合中的一项,成功返回true而不会遍历整个序列。

    14.4.4

    推迟执行

    Console.WriteLine("1,在1900年代之前的专利:");是先于Lambda表达式执行的。
    Lambda表达式在声明时不执行,除非被调用,否则其中代码不会执行。
    1. IEnumerable<Patent> patents = PatentData.Patents;  
    2. bool result;  
    3. patents = patents.Where(  
    4.     p =>  
    5.     {  
    6.         if (result = p.YearOfPublication.StartsWith("18"))  
    7.         {  
    8.             Console.WriteLine(" " + p);  
    9.         }  
    10.         return result;  
    11.     });  
    12. Console.WriteLine("1,在1900年代之前的专利:");  
    13. //1.foreach会循环分解成一个MoveNext()调用,
      //触发每项Lambda表达式
    14. foreach (var patent in patents)  
    15. {        
    16. }  
    17. Console.WriteLine();  
    18. Console.WriteLine("2.第二个清单在1900年代之前的专利:");  
    19. //2.Enumerable的Count()函数会再次触发每一项的Lambda表达式
    20. Console.WriteLine("    这里有 {0} 个专利在1900年之前..",patents.Count());  
    21. Console.WriteLine();  
    22. Console.WriteLine("3.第三个清单在1900年代之前的专利:");  
    23. //3.ToArray()(或ToList()、ToDictinary()或ToLiikup())会没想再次触发Lambda
    24. patents = patents.ToArray();  
    25. Console.Write("    这里有 ");  
    26. Console.WriteLine("{0} 个专利在1900年之前..", patents.Count());  


    执行顺序
     为了避免反复性执行,一个查询后有必要把获取的数据缓存起来。谓词可以使用“ToXXX”方法(比如ToArray())将数据赋值给一个局部集合。返回结果时,查询会执行。但此后,对赋值的集合进行遍历,就不会再设计查询表达式了。

    14.4.5

    OrderBy()和ThenBy()


    1. OrderBy()返回的是是一个IOrderEnumerable<T>接口,而不是IEnumerable<T>。  
    2. IOrderEnumerable<T>派生自 IEnumerable<T>。  
    3. OrderBy().OrderBy() 重复调用就会撤销上一个OrderBy()的工作。  
    4. 指定额外的排序条件,使用ThenBy()(ThenBy扩展自IOrderEnumerable<T>而不是IEnumerable<T>)。  

    14.4.6

    Join()内部连接


    部门和员工数据

    1. public class Department  
    2. {  
    3.     public long Id { getset; }  
    4.     public string Name { getset; }  
    5.     public override string ToString()  
    6.     {  
    7.         return string.Format("{0}", Name);  
    8.     }  
    9. }  
    10.   
    11. public class Employee  
    12. {  
    13.     public int Id { getset; }  
    14.     public string Name { getset; }  
    15.     public string Title { getset; }  
    16.     public int DepartmentId { getset; }  
    17.     public override string ToString()  
    18.     {  
    19.         return string.Format("{0}({1})", Name, Title);  
    20.     }  
    21. }  
    22.   
    23. public static class CorporateData  
    24. {  
    25.     public static readonly Department[] Departments = new Department[]  
    26.     {  
    27.         new Department() {Name = "Corporate", Id = 0},  
    28.         new Department() {Name = "Finance", Id = 1},  
    29.         new Department() {Name = "Engineering", Id = 2},  
    30.         new Department() {Name = "Information Technology", Id = 3},  
    31.         new Department() {Name = "Research", Id = 4},  
    32.         new Department() {Name = "Marketing", Id = 5},  
    33.     };  
    34.   
    35.     public static readonly Employee[] Employee = new Employee[]  
    36.     {  
    37.         new Employee() {Name = "Mark Michaelis", Title = "Chief Computer Nerd", DepartmentId = 0},  
    38.         new Employee() {Name = "Michael Stokesbary", Title = "Senior Computer Wizard", DepartmentId = 2},  
    39.         new Employee() {Name = "Brian Jones", Title = "Enterprise Integration Guru", DepartmentId = 2},  
    40.         new Employee() {Name = "Jewel Floch", Title = "Bookkeeper Extraordinaire", DepartmentId = 1},  
    41.         new Employee() {Name = "Robert Stocksbary", Title = "Expert Mainframe Engineer", DepartmentId = 3},  
    42.         new Employee() {Name = "paul R.Bramsman", Title = "Programmer Extraodinaire", DepartmentId = 2},  
    43.         new Employee() {Name = "Thomas Heavey", Title = "Software Architect", DepartmentId = 2},  
    44.         new Employee() {Name = "John Michaelis", Title = "Inventor", DepartmentId = 4},  
    45.     };  
    46. }  


    输出类...

    1. static void Main(string[] args)  
    2.  {  

    3.      Department[] departments = CorporateData.Departments;  
    4.      Employee[] employees = CorporateData.Employee;  
    5.   
    6.     //写代码......
    7.        
    8.      Console.ReadKey();  
    9.  }  
    10.   
    11.  private static void Print<T>(IEnumerable<T> items)  
    12.  {  
    13.      foreach (T item in items)  
    14.      {  
    15.          Console.WriteLine(item);  
    16.      }  
    17.  }  


    看看Join()定义的参数

    1. public static IEnumerable<TResult> Join<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, 
    2. IEnumerable<TInner> inner,                             //指定连接的集合  
    3. Func<TOuter, TKey> outerKeySelector,            //指出外接键  
    4. Func<TInner, TKey> innerKeySelector,            //指定集合的键  
    5. Func<TOuter, TInner, TResult> resultSelector);  //输出结果


    我们来输出

    1. var items = employees.Join(  
    2.     departments,//Enumerable<TInner> inner    :指定连接的集合  
    3.     employee => employee.DepartmentId,//Func<TOuter, TKey> outerKeySelector:指出外接键  
    4.     department => department.Id,// Func<TInner, TKey> innerKeySelector:指定集合的键  
    5.     (employee, department) => new  // Func<TOuter, TInner, TResult> resultSelector:输出结果  
    6.     {  
    7.         employee.Id,  
    8.         employee.Name,  
    9.         employee.Title,  
    10.         department = department  
    11.     }  
    12.     );  
    13.   
    14. Print(items);  

     

    14.4.7

    GroupBy()分组


    1. Employee[] employees = CorporateData.Employee;  
    2.   
    3. IEnumerable<IGrouping<int, Employee>> groupedEmployees =  
    4.     employees.GroupBy(e => e.DepartmentId);  
    5.   
    6. foreach (IGrouping<int, Employee> employeeGroup in groupedEmployees)  
    7. {  
    8.     Console.WriteLine();  
    9.     foreach (Employee employee in employeeGroup)  
    10.     {  
    11.         Console.WriteLine(" " + employee);  
    12.     }  
    13.     Console.WriteLine(" Count:" + employeeGroup.Count());  

     返回值为IEnumerable<IGrouping<TKey, TSource>>,根据指定的键选择器函数对序列中的元素进行分组。由于IEnumerable<IGrouping<TKey, TSource>>是从IEnumerable<T>派生的,所以可以用foreach枚举所有项。

    14.4.8

    GroupJoin()一对多关系


    如果创建员工列表,Join()提供的代码就可提供正确的结果。但是想要表示部门,理想的是显示一个部门的所有员工集合,而不是部门——员工关系都创建一条匿名类型的记录。


    先看看定义
    1. public static IEnumerable<TResult> GroupJoin<TOuter, TInner, TKey, TResult>(this IEnumerable<TOuter> outer, 
    2. IEnumerable<TInner> inner,                 //指定连接的集合
    3. Func<TOuter, TKey> outerKeySelector,  //指出外接键  
    4. Func<TInner, TKey> innerKeySelector, //指定集合的键  
    5. Func<TOuter, IEnumerable<TInner>, TResult> resultSelector);  //输出结果

    1. Department[] departments = CorporateData.Departments;  
    2. Employee[] employees = CorporateData.Employee;  
    3.   
    4. var items = departments.GroupJoin(  
    5.     employees,  
    6.     department => department.Id,  
    7.     employee => employee.DepartmentId,  
    8.     (department, departmentEmployees) => new  
    9.     {  
    10.         department.Id,  
    11.         department.Name,  
    12.         Employees = departmentEmployees  
    13.     });  
    14.   
    15. foreach (var item in items)  
    16. {  
    17.     Console.WriteLine("{0}", item.Name);  
    18.     foreach (Employee employee in item.Employees)  
    19.     {  
    20.         Console.WriteLine(" "+employee);  
    21.     }  
    22. }  


    定义里 Func<TOuter, IEnumerable<TInner>, TResult>   //输出结果
    而这里的Lambda表达式类型是
    Func<DepartmentIEnumerable<Employee>, TResult>
    其中TResult是所选的匿名类型。注意,使用第二个参数(IEnumerable<Employee>)将每个部门的员工集合投射到结果的部门匿名类型中。
    注意

    SQL中没有与GroupJoin()等价的东西,这是由于SQL返回的数据基于记录,而不分层次结构。


    14.4.9

    SelectMany()


    处理集合构成的集合。
    1. var worldCup2014Finalists = new[]  
    2. {  
    3.     new  
    4.     {  
    5.         TeamName="France",  
    6.         Players =new string[]  
    7.         {  
    8.             "本泽马","里贝里","格列兹曼","吉鲁","雷米",  
    9.             "卡巴耶","波巴","马图伊迪","瓦拉内","萨科",  
    10.             "德比希","曼加拉","穆萨-西索科","萨尼亚","埃弗拉",  
    11.             "洛里","鲁菲尔","朗德罗","马武巴","马图伊迪"  
    12.         }  
    13.     },  
    14.     new  
    15.     {  
    16.         TeamName="Italy",  
    17.         Players =new string[]  
    18.         {  
    19.             "布冯","德希利奥","基耶利尼","达米安","蒂亚戈-莫塔",  
    20.             "坎德雷瓦","阿巴特","马尔基西奥","巴洛特利","卡萨诺",  
    21.             "切尔奇","巴尔扎利","西里古","佩林","阿奎拉尼",  
    22.             "德罗西","伊莫比莱","帕罗洛","博努奇","帕莱塔"  
    23.         }  
    24.     }  
    25. };  

    IEnumerable<string> players = worldCup2014Finalists.SelectMany(t => t.Players);

    Print(players);  


    输出所有
     
    Select()SelectMany()的区别:
           Select()返回两个球员数组,每个杜对应原始集合中的球员数组。可以一边投射以便转换,但项的数量不会变化。例如:worldCup2014Finalists.Select(team => team.Players) 返回的是IEnumerable<string[]>
           SelectMany()会遍历由Lambda表达式标识的每一项,并将每项都放在一个新集合中。

    14.4.10

    更多标准查询操作符



    1. static void Main(string[] args)  
    2. {  
    3.     IEnumerable<object> stuff = new object[]  
    4.     {  
    5.         new object(),1,3,5,7,9,""thing"",Guid.NewGuid()  
    6.     };  
    7.     Print("Stuff:{0}", stuff);  
    8.     IEnumerable<int> even = new int[] {0, 2, 4, 6, 8};  
    9.     Print("【even】:{0}", even);  
    10.   
    11.     IEnumerable<int> odd = stuff.OfType<int>();//筛选指定类型<T>的元素  
    12.     Print("【odd】:{0}", odd);  
    13.   
    14.     IEnumerable<int> numbers = even.Union(odd);//并集  
    15.     Print("【numbers】odd和even的并集:{0}", numbers);  
    16.   
    17.     Print("numbers并集even(Union):{0}", numbers.Union(even));  
    18.     Print("numbers连接odd(Concat):{0}", numbers.Concat(odd));  
    19.     Print("numbers交集even(Intersection):{0}", numbers.Intersect(even));  
    20.     Print("去掉重复(Distinct):{0}", numbers.Concat(odd).Distinct());  
    21.   
    22.     if (!numbers.SequenceEqual(numbers.Concat(odd).Distinct()))  
    23.     {  
    24.         throw new Exception("Unexpectedly unequal");  
    25.     }  
    26.     else  
    27.     {  
    28.         Console.WriteLine(@"Collection ""SequenceEquals"""+  
    29.             "collection.Concat(odd).Distinct())");  
    30.         Print("反转(Reverse):{0}", numbers.Reverse());  
    31.   
    32.         Print("平均值(Average):{0}", numbers.Average());  
    33.         Print("和(Sum):{0}", numbers.Sum());  
    34.         Print("最大值(Max):{0}", numbers.Max());  
    35.         Print("最小值(Min):{0}", numbers.Min());  
    36.     }  
    37.   
    38.     Console.ReadKey();  
    39. }  
    40. private static void Print<T>(string format,IEnumerable<T> items)  
    41. {  
    42.     StringBuilder text = new StringBuilder();  
    43.     foreach (T item in items.Take(items.Count()-1))  
    44.     {  
    45.         text.Append(item + ",");  
    46.     }  
    47.     text.Append(items.Last());  
    48.   
    49.     Console.WriteLine(format,text);  
    50. }  
    51.   
    52. private static void Print<T>(string format, T item)  
    53. {  
    54.     Console.WriteLine(format, item);  
    55. }  


     













  • 相关阅读:
    python目录操作【os和os.path】
    Zabbix4.0 zabbix 快速监控主机
    Zabbix 4.0 钉钉报警
    MySql:sql99语法的连接查询
    bat脚本中存在多条指令,但只执行到某条指令不继续向下执行的一种解决方法
    基类与接口类中的虚析构函数(virtual destructor)
    TortoiseGit使用指南;
    Rust编译问题Blocking waiting for file lock on package cache
    win10安装visual C++ 6.0,在最后显示安装程序正在更新您的系统,然后就无响应
    从实现装饰者模式中思考C++指针和引用的选择
  • 原文地址:https://www.cnblogs.com/tangge/p/6052587.html
Copyright © 2020-2023  润新知