打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
16 C# 第十四章 标准查询运算符
定义
IEnumerable<T> 上的每个方法都是一个标准查询运算符(Standard Query Operator)。 它提供了对集合进行查询的能力。
注意查询运算符和查询表达式是有区别的。
这里有一个简单的例子
A simple sample show how to use.
[csharp] view plain copy
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace LinqSample01
{
class Program
{
public class Student
{
public string First { get; set; }
public string Last { get; set; }
public int ID { get; set; }
public List<int> Scores;
}
// Create a data source by using a collection initializer.
static List<Student> students = new List<Student>
{
new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores= new List<int> {97, 92, 81, 60}},
new Student {First="Claire",   Last="O’Donnell", ID=112, Scores= new List<int> {75, 84, 91, 39}},
new Student {First="Sven",     Last="Mortensen", ID=113, Scores= new List<int> {88, 94, 65, 91}},
new Student {First="Cesar",    Last="Garcia", ID=114, Scores= new List<int> {97, 89, 85, 82}},
new Student {First="Debra",    Last="Garcia", ID=115, Scores= new List<int> {35, 72, 91, 70}},
new Student {First="Fadi",     Last="Fakhouri", ID=116, Scores= new List<int> {99, 86, 90, 94}},
new Student {First="Hanying",  Last="Feng", ID=117, Scores= new List<int> {93, 92, 80, 87}},
new Student {First="Hugo",     Last="Garcia", ID=118, Scores= new List<int> {92, 90, 83, 78}},
new Student {First="Lance",    Last="Tucker", ID=119, Scores= new List<int> {68, 79, 88, 92}},
new Student {First="Terry",    Last="Adams", ID=120, Scores= new List<int> {99, 82, 81, 79}},
new Student {First="Eugene",   Last="Zabokritski", ID=121, Scores= new List<int> {96, 85, 91, 60}},
new Student {First="Michael",  Last="Tucker", ID=122, Scores= new List<int> {94, 92, 91, 91} }
};
static void Main(string[] args)
{
IEnumerable<Student> studentQuery = students.Where(
student => student.Scores[0] > 90
);
foreach (Student item in studentQuery)
{
Console.WriteLine("Name: {0}  :    {1}", item.Last, item.Scores[0]);
}
Console.ReadKey();
}
}
}
关于 Linq 查询运算符的知识点。
-  关于 IEnumerable<T>
.NET 中集合本质是一个类,这个类的关键是实现了 IEnumerable<T> 的接口。要实现对集合的遍历
关键就是要实现 IEnumerable<T> 中规定的方法。
IEnumerator 和 IEnumerable<T>的迭代器遍历。
这个与C++ STL的迭代器想法差不多,对于一个集合来说如果我们知道它具体元素的个数,我们可以使用
for (int i = 0; i < array.length; i++) 的(length-index)方式来实现遍历,但对于不知道具体元素的集合来说,
比较合适的方式是从第一个到最后一个,逐个的进行遍历。IEnumerator实现的目标就是允许使用迭代器方式来遍历。
-  集合初始化器
// Create a data source by using a collection initializer.
static List<Student> students = new List<Student>
{
new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores= new List<int> {97, 92, 81, 60}},
new Student {First="Claire",   Last="O’Donnell", ID=112, Scores= new List<int> {75, 84, 91, 39}},
...  ...
};
这段代码用了初始化数组的方式初始化了一个集合 List<Student>,但按照正常来说集合一定是在实例化好以后才能添加成员的。
其实这里使用了 C# 3.0一个新增的特性 集合初始化器。
集合初始化器要想编译成功,最理想的情况是集合支持 System.Collections.Generic.ICollection<T> 接口,这样可以保证
集合支持 Add() 方法。
并不是所有的集合都支持集合初始化器,原因有两个:
1)  并不是所有的集合都实现了ICollection<T> 接口,换个角度看就是这个接口并不是对每个集合都有用。
2)  由于方法名的匹配,例如 一个集合初始化器 支持 new DataStore(){a, {b,c}},这就表示 add()方法
要支持两种接口 add(a) 和 add(b, c),接口多样化会给程序带来方便,但有时也是负担。
-  Linq 函数
where() 筛选
IEnumerable<Student> studentQuery = students.Where(
student => student.Scores[0] > 90
);
注意:  where() 方法的表达式实参并非一定是在赋值时求值的,只有在需要遍历集合项时,才会对表达式求值。
select() 投射
select 子句可以指定将在执行查询时产生的值的类型
在最简单的情况下,select子句仅指定范围变量。这会使返回的序列包含与数据源具有相同类型的元素。
使用 select 进行结果转换:
把查询结果转换为xml格式 (http://msdn.microsoft.com/zh-cn/library/bb397914(v=vs.90).aspx)
[csharp] view plain copy
class XMLTransform
{
static void Main()
{
// Create the data source by using a collection initializer.
List<Student> students = new List<Student>()
{
new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores = new List<int>{97, 92, 81, 60}},
new Student {First="Claire", Last="O’Donnell", ID=112, Scores = new List<int>{75, 84, 91, 39}},
new Student {First="Sven", Last="Mortensen", ID=113, Scores = new List<int>{88, 94, 65, 91}},
};
// Create the query.
var studentsToXML = new XElement("Root",
from student in students
let x = String.Format("{0},{1},{2},{3}", student.Scores[0],
student.Scores[1], student.Scores[2], student.Scores[3])
select new XElement("student",
new XElement("First", student.First),
new XElement("Last", student.Last),
new XElement("Scores", x)
) // end "student"
); // end "Root"
// Execute the query.
Console.WriteLine(studentsToXML);
// Keep the console open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
Count() 计数
用来获取集合上元素个数的计数操作。功能很简单,用起来要小心。
在实例的代码中有两个打印Count数组的地方。
Console.WriteLine("ICollection<T> Count: ", students.Count());
Console.WriteLine("IEnumerable<T> Count: ", studentQuery.Count());
它们作用差不多,都是看看一共有多少个元素,但差别在于ICollection<T>有Count属性,但IEnumerable<T>
会去枚举整个的集合。
如果只是想判断一下计数是否大于 0 ---> if (IEnumerable<T>.Count() > 0) {...  ...}
那么还是替换一下吧,if (IEnumerable<T>.any()) {...  ...},这里只会尝试遍历其中的一个元素。
-  推迟执行 --- 查询的重复执行
这是一个非常重要的概念,先看一段代码,代码很简单,想要说明的问题就是在某些情况下当我们并
不想遍历整个集合时,由于IEnumerable<T>的推迟执行,在一些意想不到的地方我们还是对整个集合进行了遍历。
[csharp] view plain copy
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace DelayExecute
{
class Program
{
static void Main(string[] args)
{
// Specify the data source.
int[] scores = new int[] { 97, 92, 81, 60 };
bool result = false;
IEnumerable<int> scoreQuery = scores.Where(
score =>
{
result = false;
if (score > 80)
{
result = true;
Console.WriteLine("Score = {0}", score);
}
return result;
});
Console.WriteLine("===============================================");
Console.WriteLine("1)  Invoke empty foreeach, it will execute");
foreach (int i in scoreQuery)
{
}
Console.WriteLine("===============================================");
Console.WriteLine("2)  Invoke IEnumerable Count, it will execute");
scoreQuery.Count();
Console.WriteLine("===============================================");
Console.WriteLine("3)  Invoke IEnumerable ToArray, it will execute");
scoreQuery = scoreQuery.ToArray();
Console.ReadKey();
}
}
}
1) foreach:foreach 的本质是调用 MoveNext(),这是会触发遍历的开关。
2) Count:在前面讨论过,IEnumerable<T>的Count并不是一个属性,而是一个函数。
3) ToArray:ToXXX是个好东西,可以把集合变成可以安全操作的对象,但它同样会触发遍历,而且会把结果都加载到内存中。
下面的时序图是对推迟执行的一个简单的总结。
其他的一些查询函数
这些函数和SQL中的函数使用比较类似,可以用SQL的想法帮助理解。
OrderBy() 和 ThenBy()
[csharp] view plain copy
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestOrderAPI
{
class Program
{
public class Student
{
public string First { get; set; }
public string Last { get; set; }
public int ID { get; set; }
public List<int> Scores;
}
// Create a data source by using a collection initializer.
static List<Student> students = new List<Student>
{
new Student {First="Svetlana",    Last="Omelchenko ", ID=111, Scores= new List<int> {97, 92, 81, 60}},
new Student {First="Claire  ",    Last="O’Donnell ", ID=112, Scores= new List<int> {75, 84, 91, 39}},
new Student {First="Sven    ",    Last="Mortensen  ", ID=113, Scores= new List<int> {88, 94, 65, 91}},
new Student {First="Cesar   ",    Last="Garcia     ", ID=114, Scores= new List<int> {97, 89, 85, 82}},
new Student {First="Debra   ",    Last="Garcia     ", ID=115, Scores= new List<int> {35, 72, 91, 70}},
new Student {First="Fadi    ",    Last="Fakhouri   ", ID=116, Scores= new List<int> {99, 86, 90, 94}},
new Student {First="Hanying ",    Last="Feng       ", ID=117, Scores= new List<int> {93, 92, 80, 87}},
new Student {First="Hugo    ",    Last="Garcia     ", ID=118, Scores= new List<int> {92, 90, 83, 78}},
new Student {First="Lance   ",    Last="Tucker     ", ID=119, Scores= new List<int> {68, 79, 88, 92}},
new Student {First="Terry   ",    Last="Adams      ", ID=120, Scores= new List<int> {99, 82, 81, 79}},
new Student {First="Eugene  ",    Last="Zabokritski", ID=121, Scores= new List<int> {96, 85, 91, 60}},
new Student {First="Michael ",    Last="Tucker     ", ID=122, Scores= new List<int> {94, 92, 91, 91} }
};
static void Main(string[] args)
{
IEnumerable<Student> studentQuery = students.OrderBy(
student => student.Scores[0]).ThenBy(student => student.Scores[1]);
foreach (Student item in studentQuery)
{
Console.WriteLine("Name: {0}  :    {1},   {2}", item.Last, item.Scores[0], item.Scores[1]);
}
Console.ReadKey();
}
}
}
Join()
用于把两个集合用某中关键字连接起来。这里用的是 TeamID
[csharp] view plain copy
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestJoinAPI
{
class Program
{
public class Student
{
public string First { get; set; }
public string Last { get; set; }
public int ID { get; set; }
public List<int> Scores;
public int TeamID { get; set; }
}
public class Team
{
public int TeamID { get; set; }
public string TeamName { get; set; }
}
// Create a data source by using a collection initializer.
static List<Student> students = new List<Student>
{
new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores= new List<int> {97, 92, 81, 60}, TeamID=0},
new Student {First="Claire",   Last="O’Donnell", ID=112, Scores= new List<int> {75, 84, 91, 39}, TeamID=1},
new Student {First="Sven",     Last="Mortensen", ID=113, Scores= new List<int> {88, 94, 65, 91}, TeamID=0},
new Student {First="Cesar",    Last="Garcia", ID=114, Scores= new List<int> {97, 89, 85, 82}, TeamID=1},
new Student {First="Debra",    Last="Garcia", ID=115, Scores= new List<int> {35, 72, 91, 70}, TeamID=0},
new Student {First="Fadi",     Last="Fakhouri", ID=116, Scores= new List<int> {99, 86, 90, 94}, TeamID=1},
new Student {First="Hanying",  Last="Feng", ID=117, Scores= new List<int> {93, 92, 80, 87}, TeamID=0},
new Student {First="Hugo",     Last="Garcia", ID=118, Scores= new List<int> {92, 90, 83, 78}, TeamID=1},
new Student {First="Lance",    Last="Tucker", ID=119, Scores= new List<int> {68, 79, 88, 92}, TeamID=0},
new Student {First="Terry",    Last="Adams", ID=120, Scores= new List<int> {99, 82, 81, 79}, TeamID=1},
new Student {First="Eugene",   Last="Zabokritski", ID=121, Scores= new List<int> {96, 85, 91, 60}, TeamID=0},
new Student {First="Michael",  Last="Tucker", ID=122, Scores= new List<int> {94, 92, 91, 91}, TeamID=1 }
};
// Create a data source by using a collection initializer.
static List<Team> teams = new List<Team>
{
new Team {TeamID = 0, TeamName="Team A"},
new Team {TeamID = 1, TeamName="Team B"},
};
static void Main(string[] args)
{
var items = students.Join(teams,
student => student.TeamID,    // The key one for join
team => team.TeamID,          // The key two for join
(student, team) => new        // The new collection items
{
team.TeamID,
team.TeamName,
student.ID,
student.First,
}).OrderBy(team => team.TeamID);
foreach (var item in items)
{
Console.WriteLine("Team {0} :  {1}    {2}", item.TeamName, item.ID, item.First);
}
Console.ReadKey();
}
}
}
GroupBy()
用来对具有相似特征的对象进行分组。
[csharp] view plain copy
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestGroupByAPI
{
class Program
{
public class Student
{
public string First { get; set; }
public string Last { get; set; }
public int ID { get; set; }
public List<int> Scores;
public int TeamID { get; set; }
}
// Create a data source by using a collection initializer.
static List<Student> students = new List<Student>
{
new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores= new List<int> {97, 92, 81, 60}, TeamID=0},
new Student {First="Claire",   Last="O’Donnell", ID=112, Scores= new List<int> {75, 84, 91, 39}, TeamID=1},
new Student {First="Sven",     Last="Mortensen", ID=113, Scores= new List<int> {88, 94, 65, 91}, TeamID=0},
new Student {First="Cesar",    Last="Garcia", ID=114, Scores= new List<int> {97, 89, 85, 82}, TeamID=1},
new Student {First="Debra",    Last="Garcia", ID=115, Scores= new List<int> {35, 72, 91, 70}, TeamID=0},
new Student {First="Fadi",     Last="Fakhouri", ID=116, Scores= new List<int> {99, 86, 90, 94}, TeamID=1},
new Student {First="Hanying",  Last="Feng", ID=117, Scores= new List<int> {93, 92, 80, 87}, TeamID=0},
new Student {First="Hugo",     Last="Garcia", ID=118, Scores= new List<int> {92, 90, 83, 78}, TeamID=1},
new Student {First="Lance",    Last="Tucker", ID=119, Scores= new List<int> {68, 79, 88, 92}, TeamID=0},
new Student {First="Terry",    Last="Adams", ID=120, Scores= new List<int> {99, 82, 81, 79}, TeamID=1},
new Student {First="Eugene",   Last="Zabokritski", ID=121, Scores= new List<int> {96, 85, 91, 60}, TeamID=0},
new Student {First="Michael",  Last="Tucker", ID=122, Scores= new List<int> {94, 92, 91, 91}, TeamID=1 }
};
static void Main(string[] args)
{
IEnumerable<IGrouping<int, Student>> StudentGroup = students.GroupBy(
(student) => student.TeamID);
foreach (IGrouping<int, Student> group in StudentGroup)
{
Console.WriteLine("==========================================");
foreach (Student stu in group)
{
Console.WriteLine("Team: {0}  Name: {1}", stu.TeamID, stu.First);
}
Console.WriteLine("==========================================");
}
Console.ReadKey();
}
}
}
GroupJoin()
如果我们想知道一个小组中有多少个学生,这是一个一对多的映射,但 Join是一个一对一的映射,调用后还需要再次处理。
这时使用 GroupJoin() 是最合理的。他把小组ID 与 一组学生(多名学生)对应了起来。
[csharp] view plain copy
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace TestGroupJoinAPI
{
class Program
{
public class Student
{
public string First { get; set; }
public string Last { get; set; }
public int ID { get; set; }
public List<int> Scores;
public int TeamID { get; set; }
}
public class Team
{
public int TeamID { get; set; }
public string TeamName { get; set; }
}
// Create a data source by using a collection initializer.
static List<Student> students = new List<Student>
{
new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores= new List<int> {97, 92, 81, 60}, TeamID=0},
new Student {First="Claire",   Last="O’Donnell", ID=112, Scores= new List<int> {75, 84, 91, 39}, TeamID=1},
new Student {First="Sven",     Last="Mortensen", ID=113, Scores= new List<int> {88, 94, 65, 91}, TeamID=0},
new Student {First="Cesar",    Last="Garcia", ID=114, Scores= new List<int> {97, 89, 85, 82}, TeamID=1},
new Student {First="Debra",    Last="Garcia", ID=115, Scores= new List<int> {35, 72, 91, 70}, TeamID=0},
new Student {First="Fadi",     Last="Fakhouri", ID=116, Scores= new List<int> {99, 86, 90, 94}, TeamID=1},
new Student {First="Hanying",  Last="Feng", ID=117, Scores= new List<int> {93, 92, 80, 87}, TeamID=0},
new Student {First="Hugo",     Last="Garcia", ID=118, Scores= new List<int> {92, 90, 83, 78}, TeamID=1},
new Student {First="Lance",    Last="Tucker", ID=119, Scores= new List<int> {68, 79, 88, 92}, TeamID=0},
new Student {First="Terry",    Last="Adams", ID=120, Scores= new List<int> {99, 82, 81, 79}, TeamID=1},
new Student {First="Eugene",   Last="Zabokritski", ID=121, Scores= new List<int> {96, 85, 91, 60}, TeamID=0},
new Student {First="Michael",  Last="Tucker", ID=122, Scores= new List<int> {94, 92, 91, 91}, TeamID=1 }
};
// Create a data source by using a collection initializer.
static List<Team> teams = new List<Team>
{
new Team {TeamID = 0, TeamName="Team A"},
new Team {TeamID = 1, TeamName="Team B"},
};
static void Main(string[] args)
{
var items = teams.GroupJoin(
students,
team => team.TeamID,
student => student.TeamID,
(team, studentGroup) => new
{
team.TeamID,
team.TeamName,
students = studentGroup
});
foreach (var item in items)
{
Console.WriteLine("Team {0} : ", item.TeamName);
foreach(Student stu in item.students)
{
Console.WriteLine("Name: {0}, {1}", stu.First, stu.Last);
}
Console.WriteLine("====================================================");
}
Console.ReadKey();
}
}
}
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
C#编程初学者的应注意那些?
拿 C# 搞函数式编程 - 3
select clause (C# Reference)
C# KeyValuePair<TKey,TValue>的用法【转】 .
C# List<T>排序总结
C# List<T>的Contains, Exists, Any,Where性能对比
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服