集合访问中的LINQ查询表达式与普通方法对比

C# 中集合的概念不仅指的是System.Collection和System.Collection.Generic集合中的结合类型,实际上其他数据也可看作集合,如XML文件,数据库,数组都是集合,高效地集合操作能大大提高开发效率,C#中对于集合的操作希望做到尽量简单,统一,.NET Framework 3.5种引入的Linq(语言集成查询)实现了这一功能。

下面我们以无序的List为例,来体验linq查询表达式相对于普通集合查询的优越性。

先声明一个Book类:

1 class Book
2 {
3     public string BookName { get; set; }
4     public int PublishYear { get; set; }
5     public string Author { get; set; }
6 }
View Code

 

然后初始化一个List<Book>:

 1 List<Book> bookInstances=new List<Book>
 2 {
 3     new Book
 4     {
 5         BookName="Windows Phone 应用程序开发",
 6         PublishYear =2012,
 7         Author="李春旭"
 8     },
 9     new Book
10     {
11         BookName="Silverlight高级编程",
12         PublishYear=2011,
13         Author="李春旭"
14     },
15     new Book
16     {
17         BookName=".NET高级程序设计",
18         PublishYear=2010,
19         Author="李春旭"
20     },
21     new Book
22     {
23         BookName="精通Android应用程序",
24         PublishYear=2010,
25         Author="刘泽宏"
26     }
27 };
View Code

 

我们需要完成的三个任务:

  1. 查找书名为《.NET高级程序设计》的元素。
  2. 统计每个作者写书的数量。
  3. 找出每个作者出版的最后一本书。

一 : 普通方法

主要依靠对集合的循环遍历。

Task 1:

 1 static void Task1()
 2 {
 3     Console.WriteLine("===查找元素书名为《.NET高级程序设计》的书=======");
 4     Book theSpecialBook = null;
 5     foreach (Book item in books)
 6     {
 7         if (item.BookName.Equals(".NET高级程序设计"))
 8         {
 9             theSpecialBook = item;
10             break;
11         }
12     }
13     Console.WriteLine(theSpecialBook.BookName);
14     Console.WriteLine(theSpecialBook.Author);
15     Console.WriteLine(theSpecialBook.PublishYear);
16     Console.WriteLine();
17 }
View Code

 

Task 2:

 1 static void Task2()
 2 {
 3     Console.WriteLine("===统计每个作者共写书的数量======");
 4     Dictionary<string, int> bookCount = new Dictionary<string, int>();
 5     foreach (Book item in books)
 6     {
 7         int bookNum = 0;
 8         if (bookCount.TryGetValue(item.Author, out bookNum))
 9         {
10             bookNum++;
11             bookCount[item.Author] = bookNum;
12         }
13         else
14         {
15             bookCount.Add(item.Author, 1);
16         }
17     }
18     foreach (string key in bookCount.Keys)
19     {
20         Console.Write(key);
21         Console.WriteLine("\t" + bookCount[key]);
22     }
23     Console.WriteLine();
24 }
View Code

 

Task 3:

 1 static void Task3()
 2 {
 3     Console.WriteLine("===每个作者出版的最后一本书=====");
 4     Dictionary<string, Book> lastBookList = new Dictionary<string, Book>();
 5     foreach (Book item in books)
 6     {
 7         Book temp = null;
 8         if (lastBookList.TryGetValue(item.Author, out temp))
 9         {
10             if (item.PublishYear > temp.PublishYear)
11             {
12                 lastBookList[item.Author] = item;
13             }
14         }
15         else
16         {
17             lastBookList.Add(item.Author, item);
18         }
19     }
20 
21     foreach (string key in lastBookList.Keys)
22     {
23         Console.WriteLine(key);
24         Console.WriteLine("\t" + lastBookList[key].BookName);
25         Console.WriteLine("\t" + lastBookList[key].PublishYear);
26     }
27 }
View Code

 

至此,我们发现上述对集合的操作无外乎是遍历,区别仅是遍历的条件,次数和遍历过程中保存临时变量的内容和条件的不同,这种操作方式相对不够直观和易于理解。

二:Linq查询表达式

Task 1:

 1 static void Task1()
 2 {
 3     Console.WriteLine("===查找元素书名为《.NET高级程序设计》的书=======");
 4     IEnumerable<Book> items =
 5         (from c in books where c.BookName.Equals(".NET高级程序设计") select c);
 6     foreach (Book item in items)
 7     {
 8         Console.WriteLine(item.BookName);                
 9         Console.WriteLine(item.Author);
10         Console.WriteLine(item.PublishYear);
11         Console.WriteLine();
12     }
13 }
View Code

 

Task 2:

 1 static void Task2()
 2 {
 3     Console.WriteLine("===统计每个作者共写书的数量======");
 4     //通过group按作者名字进行分组,然后统计每组的数量
 5     var items = from c in books
 6                 group c by c.Author into d
 7                 select new              //分组之后选择出一个匿名类,使用select将数据投射为另一种类型
 8                 {                       //该匿名类有两个属性,
 9                     d.Key,              //1.作者名字
10                     Count = d.Count()   //2.书籍的数量
11                 };                      //相对于使用Dictionary来保存更加简便和直接。
12     foreach (var item in items)
13     {
14         Console.Write(item.Key);
15         Console.WriteLine("\t"+item.Count);
16     }
17     Console.WriteLine();
18 }
View Code

 

Task 3:

 1 static void Task3()
 2 {
 3     Console.WriteLine("===每个作者出版的最后一本书=====");
 4     var lastBooks = from c in books
 5                     group c by c.Author into d
 6                     let maxPubYear=d.Max<Book>(item => item.PublishYear)
 7                     select new
 8                     {
 9                         d.Key,
10                         PublishYear =maxPubYear,
11                         LastBook = from e in books  
12                                    where e.PublishYear.Equals(maxPubYear)&&e.Author.Equals(d.Key)
13                                    select e.BookName
14                     };
15     foreach (var item in lastBooks)
16     {
17         Console.WriteLine(item.Key);
18         Console.WriteLine("\t"+item.LastBook.First());
19         Console.WriteLine("\t"+item.PublishYear);
20     }
21 }
View Code

 

从上面可以看出,使用Linq,只需要一句话就能完成多行代码才能完成的功能,并且形式上更容易理解,不需要去看循环的逻辑,判断条件,循环结束条件等逻辑判断,而且不需要去设计临时变量,不用考虑如何保存遍历的结果。

使用Linq访问集合实际上是一种函数式编程,实现上述任务本质上还是调用了集合类实现的排序,查找等算法,Linq只是对相应的函数调用做了一个更易理解,更不易出错的语法描述。

完整的项目和代码可在此处下载。

posted @ 2013-08-28 16:19  FordWayne  阅读(715)  评论(4编辑  收藏  举报