开放的编程资料库

当前位置:我爱分享网 > C#教程 > 正文

C# LINQ 分组依据

在本文中,我们展示了如何使用LINQ查询在C#中对数据进行分组。

语言集成查询(LINQ)是一种特定领域的语言,用于从各种数据源(包括数组、列表、XML文件或数据库)查询数据。

groupbyinto关键字用于在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#教程。

未经允许不得转载:我爱分享网 » C# LINQ 分组依据

感觉很棒!可以赞赏支持我哟~

赞(0) 打赏