- 相關(guān)推薦
c#查詢關(guān)鍵字之group子句的使用
引導語:C#看起來與Java有著驚人的相似;它包括了諸如單一繼承、接口、與Java幾乎同樣的語法和編譯成中間代碼再運行的過程。以下是小編整理的c#查詢關(guān)鍵字之group子句的使用,歡迎參考閱讀!
group 子句返回一個 IGrouping<(Of <(TKey, TElement>)>) 對象序列,這些對象包含零個或更多個與該組的鍵值匹配的項。例如,可以按照每個字符串中的第一個字母對字符串序列進行分組。在這種情況下,第一個字母是鍵且具有 char 類型,并且存儲在每個 IGrouping<(Of <(TKey, TElement>)>) 對象的 Key 屬性中。編譯器可推斷該鍵的類型。
可以用 group 子句結(jié)束查詢表達式,如下面的示例所示:
C#
// Query variable is an IEnumerable<IGrouping<char, Student>>
var studentQuery1 =
from student in students
group student by student.Last[0];
如果您想要對每個組執(zhí)行附加查詢操作,則可以使用 into 上下文關(guān)鍵字指定一個臨時標識符。使用 into 時,必須繼續(xù)編寫該查詢,并最終用一個 select 語句或另一個 group 子句結(jié)束該查詢,如下面的代碼摘錄所示:
C#
// Group students by the first letter of their last name
// Query variable is an IEnumerable<IGrouping<char, Student>>
var studentQuery2 =
from student in students
group student by student.Last[0] into g
orderby g.Key
select g;
本主題中的“示例”部分中提供了使用含有和不含 into 的 group 的更完整示例。
枚舉組查詢的結(jié)果
由于 group 查詢產(chǎn)生的 IGrouping<(Of <(TKey, TElement>)>) 對象實質(zhì)上是列表的列表,因此必須使用嵌套的 foreach 循環(huán)來訪問每一組中的各個項。外部循環(huán)用于循環(huán)訪問組鍵,內(nèi)部循環(huán)用于循環(huán)訪問組本身中的每個項。組可能具有鍵,但沒有元素。以下是執(zhí)行上述代碼示例中的查詢的 foreach 循環(huán):
C#
// Iterate group items with a nested foreach. This IGrouping encapsulates
// a sequence of Student objects, and a Key of type char.
// For convenience, var can also be used in the foreach statement.
foreach (IGrouping<char, Student> studentGroup in studentQuery2)
{
Console.WriteLine(studentGroup.Key);
// Explicit type for student could also be used here.
foreach (var student in studentGroup)
{
Console.WriteLine(" {0}, {1}", student.Last, student.First);
}
}
鍵類型
組鍵可以是任何類型,如字符串、內(nèi)置數(shù)值類型、用戶定義的命名類型或匿名類型。
按字符串進行分組
上述代碼示例使用的是 char。可以很容易地改為指定字符串鍵,如完整的姓氏:
C#
// Same as previous example except we use the entire last name as a key.
// Query variable is an IEnumerable<IGrouping<string, Student>>
var studentQuery3 =
from student in students
group student by student.Last;
按布爾進行分組
下面的示例演示使用布爾值作為鍵將結(jié)果劃分成兩個組。請注意,該值是由 group 子句中的子表達式產(chǎn)生的。
C#
class GroupSample1
{
// The element type of the data source.
public class Student
{
public string First { get; set; }
public string Last { get; set; }
public int ID { get; set; }
public List<int> Scores;
}
public static List<Student> GetStudents()
{
// Use a collection initializer to create the data source. Note that each element
// in the list contains an inner sequence of scores.
List<Student> students = new List<Student>
{
new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores= new List<int> {97, 72, 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> {99, 89, 91, 95}},
new Student {First="Cesar", Last="Garcia", ID=114, Scores= new List<int> {72, 81, 65, 84}},
new Student {First="Debra", Last="Garcia", ID=115, Scores= new List<int> {97, 89, 85, 82}}
};
return students;
}
static void Main()
{
// Obtain the data source.
List<Student> students = GetStudents();
// Group by true or false.
// Query variable is an IEnumerable<IGrouping<bool, Student>>
var booleanGroupQuery =
from student in students
group student by student.Scores.Average() >= 80; //pass or fail!
// Execute the query and access items in each group
foreach (var studentGroup in booleanGroupQuery)
{
Console.WriteLine(studentGroup.Key == true ? "High averages" : "Low averages");
foreach (var student in studentGroup)
{
Console.WriteLine(" {0}, {1}:{2}", student.Last, student.First, student.Scores.Average());
}
}
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
/* Output:
Low averages
Omelchenko, Svetlana:77.5
O'Donnell, Claire:72.25
Garcia, Cesar:75.5
High averages
Mortensen, Sven:93.5
Garcia, Debra:88.25
*/
按數(shù)值范圍進行分組
下一個示例使用表達式創(chuàng)建表示百分比范圍的數(shù)值組鍵。請注意,該示例使用 let 作為方法調(diào)用結(jié)果的方便存儲位置,從而無需在 group 子句中調(diào)用該方法兩次。另請注意,在 group 子句中,為了避免發(fā)生“被零除”異常,代碼進行了相應檢查以確保學生的平均成績不為零。有關(guān)如何在查詢表達式中安全使用方法的更多信息,請參見如何:在查詢表達式中處理異常(C# 編程指南)。
C#
class GroupSample2
{
// The element type of the data source.
public class Student
{
public string First { get; set; }
public string Last { get; set; }
public int ID { get; set; }
public List<int> Scores;
}
public static List<Student> GetStudents()
{
// Use a collection initializer to create the data source. Note that each element
// in the list contains an inner sequence of scores.
List<Student> students = new List<Student>
{
new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores= new List<int> {97, 72, 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> {99, 89, 91, 95}},
new Student {First="Cesar", Last="Garcia", ID=114, Scores= new List<int> {72, 81, 65, 84}},
new Student {First="Debra", Last="Garcia", ID=115, Scores= new List<int> {97, 89, 85, 82}}
};
return students;
}
// This method groups students into percentile ranges based on their
// grade average. The Average method returns a double, so to produce a whole
// number it is necessary to cast to int before dividing by 10.
static void Main()
{
// Obtain the data source.
List<Student> students = GetStudents();
// Write the query.
var studentQuery =
from student in students
let avg = (int)student.Scores.Average()
group student by (avg == 0 ? 0 : avg / 10) into g
orderby g.Key
select g;
// Execute the query.
foreach (var studentGroup in studentQuery)
{
int temp = studentGroup.Key * 10;
Console.WriteLine("Students with an average between {0} and {1}", temp, temp + 10);
foreach (var student in studentGroup)
{
Console.WriteLine(" {0}, {1}:{2}", student.Last, student.First, student.Scores.Average());
}
}
// Keep the console window open in debug mode.
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
/* Output:
Students with an average between 70 and 80
Omelchenko, Svetlana:77.5
O'Donnell, Claire:72.25
Garcia, Cesar:75.5
Students with an average between 80 and 90
Garcia, Debra:88.25
Students with an average between 90 and 100
Mortensen, Sven:93.5
*/
按復合鍵進行分組
當您想要按照多個鍵對元素進行分組時,可使用復合鍵。通過使用匿名類型或命名類型來存儲鍵元素,可以創(chuàng)建復合鍵。在下面的示例中,假定已經(jīng)使用名為 surname 和 city 的兩個成員聲明了類 Person。group 子句使得為每組具有相同姓氏和相同城市的人員創(chuàng)建一個單獨的組。
復制代碼
group person by new {name = person.surname, city = person.city};
如果必須將查詢變量傳遞給其他方法,請使用命名類型。使用自動實現(xiàn)的屬性作為鍵來創(chuàng)建一個特殊類,然后重寫 Equals 和 GetHashCode 方法。還可以使用結(jié)構(gòu);在此情況下,并不絕對需要重寫這些方法。有關(guān)更多信息,請參見如何:使用自動實現(xiàn)的屬性實現(xiàn)輕量類(C# 編程指南)和如何:在目錄樹中查詢重復文件 (LINQ)。后一個主題包含一個代碼示例,該示例演示如何將復合鍵與命名類型結(jié)合使用。
示例
下面的示例演示在沒有向組應用附加查詢邏輯時將源數(shù)據(jù)排序放入不同組中的標準模式。這稱為不帶延續(xù)的分組。字符串數(shù)組中的元素按照它們的第一個字母進行分組。查詢結(jié)果是一個 IGrouping<(Of <(TKey, TElement>)>) 類型,其中包含一個 char 類型的公共 Key 屬性以及一個包含分組中每個項的 IEnumerable<(Of <(T>)>) 集合。
group 子句的結(jié)果是序列的序列。因此,若要訪問所返回的每個組中的單個元素,請在循環(huán)訪問組鍵的循環(huán)內(nèi)使用嵌套的 foreach 循環(huán),如下面的示例所示。
C#
class GroupExample1
{
static void Main()
{
// Create a data source.
string[] words = { "blueberry", "chimpanzee", "abacus", "banana", "apple", "cheese" };
// Create the query.
var wordGroups =
from w in words
group w by w[0];
// Execute the query.
foreach (var wordGroup in wordGroups)
{
Console.WriteLine("Words that start with the letter '{0}':", wordGroup.Key);
foreach (var word in wordGroup)
{
Console.WriteLine(word);
}
}
// Keep the console window open in debug mode
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
/* Output:
Words that start with the letter 'b':
blueberry
banana
Words that start with the letter 'c':
chimpanzee
cheese
Words that start with the letter 'a':
abacus
apple
*/
此示例演示在創(chuàng)建組之后,如何使用通過 into 實現(xiàn)的延續(xù)對這些組執(zhí)行附加邏輯。有關(guān)更多信息,請參見 into(C# 參考)。下面的示例查詢每個組以僅選擇那些鍵值為元音的元素。
C#
class GroupClauseExample2
{
static void Main()
{
// Create the data source.
string[] words2 = { "blueberry", "chimpanzee", "abacus", "banana", "apple", "cheese", "elephant", "umbrella", "anteater" };
// Create the query.
var wordGroups2 =
from w in words2
group w by w[0] into grps
where (grps.Key == 'a' || grps.Key == 'e' || grps.Key == 'i'
|| grps.Key == 'o' || grps.Key == 'u')
select grps;
// Execute the query.
foreach (var wordGroup in wordGroups2)
{
Console.WriteLine("Groups that start with a vowel: {0}", wordGroup.Key);
foreach (var word in wordGroup)
{
Console.WriteLine(" {0}", word);
}
}
// Keep the console window open in debug mode
Console.WriteLine("Press any key to exit.");
Console.ReadKey();
}
}
/* Output:
Groups that start with a vowel: a
abacus
apple
anteater
Groups that start with a vowel: e
elephant
Groups that start with a vowel: u
umbrella
*/
備注
編譯時,group 子句被轉(zhuǎn)換為對 GroupBy 方法的調(diào)用。
【c#查詢關(guān)鍵字之group子句的使用】相關(guān)文章:
c#中預處理指令#if的使用11-30
c#檢測cpu使用率12-05
Java編程中this關(guān)鍵字與super關(guān)鍵字的使用方法04-02
C#數(shù)據(jù)結(jié)構(gòu)之循環(huán)鏈表的實例代碼12-04
職稱英語成績查詢之合格標準03-29
Java編程中throw和throws子句的使用方法04-03
PHP中this關(guān)鍵字03-28
淘寶裝修之DW熱點工具使用03-31
理解java中的關(guān)鍵字04-02