在本文中,我们展示了如何使用LINQ查询在C#中对数据进行分组。
语言集成查询(LINQ)是一种特定领域的语言,用于从各种数据源(包括数组、列表、XML文件或数据库)查询数据。
group
、by
和into
关键字用于在LINQ中对数据进行分组。
可以按以下方式对数据进行分组:
- 单个键
- 一个属性
- 一个复合键
- 一个计算的数值范围
- 一个表达式
C#LINQ按键分组
我们可以根据某个键将数据分组。
var cars = new List<Car> { new ("Audi", "red", 52642), new ("Mercedes", "blue", 57127), new ("Skoda", "black", 9000), new ("Volvo", "red", 29000), new ("Bentley", "yellow", 350000), new ("Citroen", "white", 21000), new ("Hummer", "black", 41400), new ("Volkswagen", "white", 21600), }; var groups = from car in cars group car by car.Colour; foreach (var group in groups) { Console.WriteLine(group.Key); foreach (var car in group) { Console.WriteLine($" {car.Name} {car.Price}"); } } record Car(string Name, string Colour, int Price);
我们按颜色将汽车分组。
$ dotnet run red Audi 52642 Volvo 29000 blue Mercedes 57127 black Skoda 9000 Hummer 41400 yellow Bentley 350000 white Citroen 21000 Volkswagen 21600
C#LINQ按属性分组
我们可以根据元素的某些属性对数据进行分组。
var words = new List<string> { "war", "water", "cup", "cloud", "atom", "abyss", "soup", "book", "moon", "nice", "sky", "forest" }; var groups = from word in words group word by word.Length; foreach (var group in groups) { Console.WriteLine(group.Key); foreach (var e in group) { Console.WriteLine($"{e}"); } Console.WriteLine("----------------"); }
该示例按长度对单词进行分组。
$ dotnet run 3 war cup sky ---------------- 5 water cloud abyss ---------------- 4 atom soup book moon nice ---------------- 6 forest ----------------
C#LINQ分组和聚合
在下面的示例中,我们执行分组和聚合操作。
Revenue[] revenues = { new (1, "Q1", 2340), new (2, "Q1", 1200), new (3, "Q1", 980), new (4, "Q2", 340), new (5, "Q2", 780), new (6, "Q3", 2010), new (7, "Q3", 3370), new (8, "Q4", 540), }; var res = from revenue in revenues group revenue by revenue.Quarter into g select new { Quarter = g.Key, Total = g.Sum(e => e.Amount) }; foreach (var line in res) { Console.WriteLine(line); } record Revenue(int Id, string Quarter, int Amount);
我们有四个季度的收入。我们按季度对收入进行分组并对金额求和。
$ dotnet run { Quarter = Q1, Total = 4520 } { Quarter = Q2, Total = 1120 } { Quarter = Q3, Total = 5380 } { Quarter = Q4, Total = 540 }
我们可以使用where
子句对聚合数据应用过滤器。
Revenue[] revenues = { new (1, "Q1", 2340), new (2, "Q1", 1200), new (3, "Q1", 980), new (4, "Q2", 340), new (5, "Q2", 780), new (6, "Q3", 2010), new (7, "Q3", 3370), new (8, "Q4", 540), }; var res = from revenue in revenues group revenue by revenue.Quarter into g where g.Count() == 2 select new { Quarter = g.Key, Total = g.Sum(c => c.Amount) }; foreach (var line in res) { Console.WriteLine(line); } record Revenue(int Id, string Quarter, int Amount);
在示例中,我们仅选择恰好有两个收入的那些季度。
$ dotnet run { Quarter = Q2, Total = 1120 } { Quarter = Q3, Total = 5380 }
C#LINQ按复合键分组
我们可以通过由多个字段组成的组合键对数据进行分组。
User[] users = { new ("John", "Doe", "gardener"), new ("Jane", "Doe", "teacher"), new ("Roger", "Roe", "driver"), new ("Peter", "Doe", "teacher"), new ("Pavol", "Novak", "programmer"), new ("Albert", "Novak", "teacher"), new ("Sam", "Novak", "driver"), new ("Peter", "Horvath", "accountant"), new ("Lucia", "Horvath", "accountant"), new ("Michael", "Novak", "programmer"), }; var groups = from user in users group user by new { user.LastName, user.Occupation }; foreach (var group in groups) { Console.WriteLine(group.Key); foreach (var e in group) { Console.WriteLine($"{e}"); } Console.WriteLine("----------------"); } record User(string FirstName, string LastName, string Occupation);
该程序按姓氏和职业排列用户组。
$ dotnet run { LastName = Doe, Occupation = gardener } User { FirstName = John, LastName = Doe, Occupation = gardener } ---------------- { LastName = Doe, Occupation = teacher } User { FirstName = Jane, LastName = Doe, Occupation = teacher } User { FirstName = Peter, LastName = Doe, Occupation = teacher } ---------------- { LastName = Roe, Occupation = driver } User { FirstName = Roger, LastName = Roe, Occupation = driver } ---------------- { LastName = Novak, Occupation = programmer } User { FirstName = Pavol, LastName = Novak, Occupation = programmer } User { FirstName = Michael, LastName = Novak, Occupation = programmer } ---------------- { LastName = Novak, Occupation = teacher } User { FirstName = Albert, LastName = Novak, Occupation = teacher } ---------------- { LastName = Novak, Occupation = driver } User { FirstName = Sam, LastName = Novak, Occupation = driver } ---------------- { LastName = Horvath, Occupation = accountant } User { FirstName = Peter, LastName = Horvath, Occupation = accountant } User { FirstName = Lucia, LastName = Horvath, Occupation = accountant } ----------------
C#LINQgroupby布尔表达式
在下面的示例中,我们使用布尔表达式对数据进行分组。
Student[] students = { new ("John", "Doe", 78), new ("Roger", "Roe", 89), new ("Peter", "Doe", 90), new ("Pavol", "Novak", 34), new ("Albert", "Novak", 66), new ("Peter", "Horvath", 89), new ("Lucia", "Horvath", 88), new ("Michael", "Novak", 99), }; var groups = from student in students group student by new { Passed = student.Score > 70, }; foreach (var group in groups) { if (group.Key.Passed) { Console.WriteLine("passed"); } else { Console.WriteLine("failed"); } foreach (var e in group) { Console.WriteLine(e); } Console.WriteLine("----------------------------"); } record Student(string FirstName, string LastName, int Score);
我们有一组包含名字、姓氏和分数字段的学生记录。要通过考试,学生的分数必须超过70。使用LINQ表达式,我们将学生分为两组:通过和未通过。
$ dotnet run passed Student { FirstName = John, LastName = Doe, Score = 78 } Student { FirstName = Roger, LastName = Roe, Score = 89 } Student { FirstName = Peter, LastName = Doe, Score = 90 } Student { FirstName = Peter, LastName = Horvath, Score = 89 } Student { FirstName = Lucia, LastName = Horvath, Score = 88 } Student { FirstName = Michael, LastName = Novak, Score = 99 } ---------------------------- failed Student { FirstName = Pavol, LastName = Novak, Score = 34 } Student { FirstName = Albert, LastName = Novak, Score = 66 } ----------------------------
C#LINQ按范围分组
在下一个示例中,我们使用数字范围作为组键。
var students = new List<Student> { new ("John", "Doe", 78), new ("Roger", "Roe", 89), new ("Peter", "Doe", 90), new ("Pavol", "Novak", 34), new ("Albert", "Novak", 66), new ("Peter", "Horvath", 89), new ("Lucia", "Horvath", 88), new ("Michael", "Novak", 99), }; var groups = from std in students let avg = students.Average(e => e.Score) group std by (std.Score / 10) into g orderby g.Key select g; foreach (var group in groups) { Console.WriteLine(group.Key * 10); foreach (var e in group) { Console.WriteLine(e); } Console.WriteLine("----------------------------"); } record Student(string FirstName, string LastName, int Score);
该示例将学生分组到百分位数范围内。
$ dotnet run 30 Student { FirstName = Pavol, LastName = Novak, Score = 34 } ---------------------------- 60 Student { FirstName = Albert, LastName = Novak, Score = 66 } ---------------------------- 70 Student { FirstName = John, LastName = Doe, Score = 78 } ---------------------------- 80 Student { FirstName = Roger, LastName = Roe, Score = 89 } Student { FirstName = Peter, LastName = Horvath, Score = 89 } Student { FirstName = Lucia, LastName = Horvath, Score = 88 } ---------------------------- 90 Student { FirstName = Peter, LastName = Doe, Score = 90 } Student { FirstName = Michael, LastName = Novak, Score = 99 } ----------------------------
C#LINQ词频
在下面的示例中,我们计算文件中单词的出现频率。
$ wget https://raw.githubusercontent.com/janbodnar/data/main/the-king-james-bible.txt
我们从钦定版圣经中读取数据。
using System.Text.RegularExpressions; var fileName = "the-king-james-bible.txt"; var text = File.ReadAllText(fileName); var dig = new Regex(@"\d"); var matches = new Regex("[a-z-A-Z']+").Matches(text); var words = from match in matches let val = match.Value where !dig.IsMatch(val) select match.Value; var topTen = (from word in words group word by word into wg orderby wg.Count() descending select new {word = wg.Key, Total = wg.Count()} ).Take(10); foreach (var e in topTen) { Console.WriteLine($"{e.word}: {e.Total}"); }
我们计算KingJames圣经中单词的出现频率。
var matches = new Regex("[a-z-A-Z']+").Matches(text); var words = matches.Select(m => m.Value).ToList();
我们通过Matches
方法找到所有匹配项。从matchcollection中,我们将所有单词放入一个列表中。
var words = from match in matches let val = match.Value where !dig.IsMatch(val) select match.Value;
在第一个查询中,我们找到了所有匹配项。从匹配集合中,我们得到了所有的单词。
var topTen = (from word in words group word by word into wg orderby wg.Count() descending select new {word = wg.Key, Total = wg.Count()} ).Take(10);
单词按频率降序分组和排序。我们取前十个最常用的词。
$ dotnet run the 62103 and 38848 of 34478 to 13400 And 12846 that 12576 in 12331 shall 9760 he 9665 unto 8942
在本文中,我们在C#LINQ中对数据进行了分组。
列出所有C#教程。