جملة group (مرجع #C)
جملة group ترجع تسلسل من كائنات IGrouping<TKey, TElement> تحتوي على صفر أو أكثر من العناصر التي تطابق قيمة المفتاح للمجموعة. على سبيل المثال، يمكنك تجميع تسلسل سلاسل حرفية حسب الحرف الأول في كل سلسلة. في هذه الحالة، الحرف الأول هو المفتاح وهو من نوع char ويتم تخزينه في خاصية Key لكل كائن IGrouping<TKey, TElement>. المحول البرمجي يستدل على نوع المفتاح.
يمكنك إنهاء تعبير استعلام بجملة group كما هو موضح في المثال التالي:
// Query variable is an IEnumerable<IGrouping<char, Student>>
var studentQuery1 =
from student in students
group student by student.Last[0];
إذا كنت ترغب بالقيام في عمليات استعلام إضافية على كل مجموعة يمكنك تحديد معرّف مؤقت باستخدام الكلمة الأساسية السياقية into. عند استخدام into يجب المتابعة مع الاستعلام، وأخيراً تنهيها إما بعبارة select أو جملة group كما هو موضح في المقتطف التالي:
// 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;
توجد أمثلة كاملة أكثر على استخدام group مع أو بدون into في مقطع الأمثلة في هذا الموضوع.
تعداد نتائج استعلام المجموعة
لأن كائنات IGrouping<TKey, TElement> التي تم إنتاجها من قبل استعلام group بشكل أساسي عبارة عن قائمة من قوائم يجب استخدام تكرار حلقي متداخل foreach للوصول إلى عناصر كل مجموعة. التكرار الحلقي الخارجي يمر عبر مفاتيح المجموعة والتكرار الحلقي الداخلي يمر عبر كل عنصر في المجموعة. قد يكون لدى المجموعة مفتاح ولكن لا يكون لديها عناصر. التالي هو تكرار حلقي foreach يقوم بتنفيذ الاستعلام في أمثلة تعليمات برمجية سابقة:
// 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);
}
}
أنواع مفاتيح
يمكن لمفاتيح المجموعة أن تكون من أي نوع مثل سلسلة حرفية أو نوع عددي مضمن أو نوع مسمى معرف من قبل المستخدم أو نوع مجهول.
التجميع حسب السلسلة
أمثلة التعليمات البرمجية السابقة استخدمت char. يمكن تحديد مفتاح السلسلة الحرفية بدلاً من ذلك، على سبيل المثال الاسم أخير:
// 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;
التجميع حسب المنطقية
يوضح المثال التالي استخدام قيمة منطقية للمفتاح لتقسيم النتائج في مجموعتين. لاحظ أنه يتم انتاج القيمة عن طريق تعبير فرعي في جملة group.
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
*/
التجميع حسب النطاق الرقمي
يستخدم المثال التالي تعبير لإنشاء مفاتيح مجموعات رقمية تمثل نطاق قيمة مئوية. لاحظ استخدام let كموقع ملائم لتخزين نتيجة استدعاء أسلوب, بحيث لا يجب عليك استدعاء الأسلوب مرتين في جملة group. لاحظ أيضاً في جملة group التي تتجنب استثناء "القسمة على صفر" تختبر التعليمات البرمجية لتتأكد من أنه لا يحتوي متوسط الطالب على صفر. للحصول على معلومات أكثر حول كيفية استخدام الأساليب بأمان في تعبيرات الاستعلام، راجع كيفية القيام بما يلي: التعامل مع الاستثناءات في تعبيرات الاستعلام ( دليل البرمجة 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
*/
التجميع حسب المفاتيح المركبة
استخدم مفتاح مركب عندما ترغب في تجميع عناصر حسب مفتاح واحد أو أكثر. تقوم بإنشاء مفتاح مركب باستخدام نوع مجهول أو نوع مسمى للحفاظ على عنصر المفتاح. في المثال التالي، افترض أنه تم تعريف الفئة Person مع الأعضاء surname و city. جملة group تؤدي إلى إنشاء مجموعة منفصلة لكل مجموعة من الأشخاص الذين لديهم نفس اسم العائلة والمدينة نفسها.
group person by new {name = person.surname, city = person.city};
استخدم نوع مسمى إذا كان يجب عليك تمرير متغير استعلام إلى أسلوب آخر. قم بإنشاء فئة خاصة باستخدام خصائص ذات تنفيذ تلقائي للمفاتيح ومن ثم تجاوز الأساليب Equals و GetHashCode. يمكنك أيضاً استخدام بنية, وفي هذه الحالة لا يجب عليك تجاوز تلك الأساليب. و للمزيد من المعلومات ، راجع كيفية القيام بما يلي: تنفيذ الفئة الصغيرة مع خصائص التنفيذ التلقائي ( ارشادات البرمجة C# ) و كيفية: الاستعلام عن الملفات المكررة في شجرة دليل (LINQ) . يحتوي الموضوع الأخير مثال عن التعليمات البرمجية التي توضح كيفية استخدام مفتاح مركب بنوع مسمى.
مثال
يظهر المثال التالي النمط القياسي لترتيب بيانات المصدر إلى مجموعات عند عدم تطبيق أي منطق استعلام إضافي للمجموعات. يسمى هذا تجميع دون متابعة. يتم تجميع العناصر في صفيف سلاسل حرفية حسب الحرف الأول. نتيجة الاستعلام من نوع IGrouping<TKey, TElement> يحتوي على خاصية عامة Key من نوع char ومجموعة IEnumerable<T> تحتوي على كل عنصر في التجميع.
نتيجة جملة group عبارة عن تسلسل تسلسلات. ولذلك، للوصول إلى عناصر فردية داخل كل مجموعة تم إرجاعها، استخدم تكرار حلقي متداخل foreach داخل الحلقة التي تمر عبر مفاتيح المجموعة كما هو موضح في المثال التالي.
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
*/
يوضح هذا المثال كيفية تنفيذ منطق إضافي على المجموعات بعد إنشائها، وذلك باستخدام متابعة عن طريق into. لمزيد من المعلومات، راجع into (مرجع #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 إلى استدعاءات أسلوب GroupBy.
راجع أيضًا:
المهام
كيفية القيام بما يلي: تجميع مجموعة (دليل البرمجة لـ #C)
كيفية القيام بما يلي: تجميع النتائج في طرق متعددة (دليل البرمجة لـ #C)
كيفية القيام بما يلي: تنفيذ استعلام فرعي لعملية التجميع ( ارشادات برمجة C# )
المرجع
المبادئ
LINQ استعلام التعبيرات (C# البرمجة الدليل)