4 其他标准查询操作符(More Standard Query Operators)
在最上面描述的基本的查询技巧(query facilities)中,许多操作符(a number of operators)提供有用的方式(useful ways)来操作序列(manipulating sequences)和组装查询(composing queries),通过使用便利(convenient)的标准查询操作符(standard query operators)的框架(framework)让用户在结果(over the result)之上有很高的控制程度(high degree of control)。
4.1 排序和分组操作(Sorting and Grouping)
通常(In general),查询表达式(query expression)的赋值(evaluation)导致(产生)(results in)的一个序列的值(sequence of values),并且以某种顺序(in some order)产生(produced),这是基本的信息源(the underlying information sources)的固有性质(intrinsic)。为了让开发者清楚地控制(explicit control)数据序列产生的顺序,所以定义了标准查询操作符(standard query operators)来控制顺序(controlling the order)。其中最基本的操作符就是 OrderBy 。
OrderBy 和OrderByDescending 操作符可以用来应用于任何信息源(any information source),允许用户提供一个制造出(produces)用来给结果排序(used to sort the results)的值的一个关键词分解函数(key extraction function)。OrderBy 和OrderByDescending 操作符也可以接收(accept)可选的比较函数(optional comparison function),这个函数可以用来给关键词(keys)的排序强加上(impose)一个次序的排序(partial order)。让我们看看下面这段基础的例子:
"Albert", "George", "Harris", "David" };
// unity sort
var s1 = names.OrderBy(s => s);
var s2 = names.OrderByDescending(s => s);
// sort by length
var s3 = names.OrderBy(s => s.Length);
var s4 = names.OrderByDescending(s => s.Length);
前面两个查询表达式产生新的序列是基于字符串比较(based on string comparison)的对数据源成员的排序方式(based on sorting the members of the source)产生的。下面两个查询产生的序列是基于每个字符串长度(based on the length of each string)的对数据源成员的排序(sorting the members of the source)方式产生的。
为了允许多次排序的标准(multiple sort criteria),OrderBy 和 OrderByDescending 操作符都返回 SortedSequence<T> 接口 而不是通常的 IEnumerable<T>.接口。两个只定义在 SortedSequence<T> 接口之上的操作符,被称作 ThenBy 和 ThenByDescending,它们用来应用一个附加的(并且次序的)的排序标准(additional (subordinate) sort criterion)。ThenBy/ThenByDescending 操作符它们自己返回 SortedSequence<T> 接口,而且允许应用许多(any number of)次 ThenBy/ThenByDescending 操作符:
"Albert", "George", "Harris", "David" };
var s1 = names.OrderBy(s => s.Length).ThenBy(s => s);
在这个例子中,变量 s1 所引用(referenced)的查询的赋值(Evaluating the query)将产生出(yield)下面的值的序列(sequence of values):
"Albert", "Connor", "George", "Harris",
"Everett"
除了(In addition to)OrderBy 种类的操作符(OrderBy family of operators),标准查询操作符(standard query operators)还包括一个 Reverse 操作符。Reverse 操作符简单地在一个序列上进行枚举(enumerates)操作,产生(yields)一个以相反顺序排序(in reverse order)的包含相同成员的一组值。与 OrderBy 不同,Reverse 在决定排序(determining the order)的时候不考虑那些值自己的真实内容(actual values themselves),而是单独地依靠(relies solely)基本数据源(the underlying source)所产成的值的顺序。
OrderBy 操作符影响(imposes)一组值的序列(a sequence of values)的排列顺序(a sort order)。标准查询操作符还包括 GroupBy 操作符,它影响一组值的序列的分割(partitioning),基于一个关键词分解函数(a key extraction function)。GroupBy 操作符返回一个分组的值(Grouping values)的序列,一组会遇到的每一个单独的关键词的值的序列(one for each distinct key value that was encountered)。每一分组(each grouping)既包含了关键词(key)又(as well as)包含了映射到(mapped to)这个 key 的那一组值(the group of values)。分组(Grouping)的公开标识(public contract)看起来像如下的代码:
public Grouping(K key, IEnumerable<T> group);
public Grouping();
public K Key { get; set; }
public IEnumerable<T> Group { set; get; }
}
最简单的使用 GroupBy 程序看起来如下所示:
"Everett", "Frank", "George", "Harris"};
// group by length
var grouping = names.GroupBy(s => s.Length);
foreach (Grouping<int, string> group in grouping) {
Console.WriteLine("Strings of length {0}", group.Key);
foreach (string value in group.Group)
Console.WriteLine(" {0}", value);
}
当运行后,此段程序将打印出如下的结果:
Albert
Connor
George
Harris
Strings of length 5
Burke
David
Frank
Strings of length 7
Everett
Select 和 GroupBy 关键词允许你提供一个映射函数(projection function)来移动分组的成员(populate members of the groups):
"Everett", "Frank", "George", "Harris"};
// group by length
var grouping = names.GroupBy(s => s.Length,
s => s[0]);
foreach (Grouping<int, char> group in grouping) {
Console.WriteLine("Strings of length {0}", group.Key);
foreach (char value in group.Group)
Console.WriteLine(" {0}", value);
}
这个变化(variation)将打印出如下结果:
A
C
G
H
Strings of length 5
B
D
F
Strings of length 7
E
从这个例子中需要注意的是,投影类型(projected type)不需要跟数据源一模一样。既然这样(In this case),我们从一个字符串的序列(a sequence of strings)创建了一个从整型(integers)到字符(characters)的分组。
待续, 错误难免,请批评指正,译者Naven
No comments:
Post a Comment