跳转到内容

C Sharp LINQ 分组(Grouping)

来自代码酷

C# LINQ 分组(Grouping)[编辑 | 编辑源代码]

LINQ(Language Integrated Query) 是 C# 中用于查询数据的强大工具,而 分组(Grouping) 是其中一项核心功能,允许开发者按照指定的键(Key)将数据集合划分为多个逻辑组。分组操作在数据分析、报表生成和数据聚合等场景中非常有用。

基本概念[编辑 | 编辑源代码]

在 LINQ 中,分组操作通过 GroupBy 方法实现。该方法接受一个键选择器(Key Selector)函数,并返回一个分组集合,其中每个分组包含具有相同键的元素。

数学上,分组操作可以表示为: G={gg={xSf(x)=k} for some k} 其中:

  • S 是源数据集合,
  • f 是键选择器函数,
  • k 是分组键,
  • G 是分组后的结果。

基本语法[编辑 | 编辑源代码]

GroupBy 方法的基本语法如下:

IEnumerable<IGrouping<TKey, TSource>> GroupBy<TSource, TKey>(
    this IEnumerable<TSource> source,
    Func<TSource, TKey> keySelector
);

其中:

  • TSource 是源数据类型,
  • TKey 是分组键的类型,
  • keySelector 是一个函数,用于从元素中提取分组键。

示例代码[编辑 | 编辑源代码]

以下是一个简单的示例,展示如何使用 GroupBy 对一组学生按班级进行分组:

using System;
using System.Linq;
using System.Collections.Generic;

class Student
{
    public string Name { get; set; }
    public int Class { get; set; }
    public int Score { get; set; }
}

class Program
{
    static void Main()
    {
        List<Student> students = new List<Student>
        {
            new Student { Name = "Alice", Class = 1, Score = 85 },
            new Student { Name = "Bob", Class = 2, Score = 90 },
            new Student { Name = "Charlie", Class = 1, Score = 78 },
            new Student { Name = "David", Class = 2, Score = 92 },
            new Student { Name = "Eve", Class = 3, Score = 88 }
        };

        var groupedStudents = students.GroupBy(s => s.Class);

        foreach (var group in groupedStudents)
        {
            Console.WriteLine($"Class {group.Key}:");
            foreach (var student in group)
            {
                Console.WriteLine($"- {student.Name}, Score: {student.Score}");
            }
        }
    }
}

输出:

Class 1:
- Alice, Score: 85
- Charlie, Score: 78
Class 2:
- Bob, Score: 90
- David, Score: 92
Class 3:
- Eve, Score: 88

解释[编辑 | 编辑源代码]

1. 定义了一个 Student 类,包含学生的姓名、班级和分数。 2. 创建了一个 List<Student>,包含 5 个学生数据。 3. 使用 GroupBy(s => s.Class) 按班级分组。 4. 遍历分组结果,打印每个班级的学生信息。

分组后的操作[编辑 | 编辑源代码]

分组后,可以对每个组进行进一步的操作,例如计算每组的平均值、最大值或最小值。

示例:计算每班的平均分[编辑 | 编辑源代码]

var averageScores = students.GroupBy(s => s.Class)
                           .Select(g => new
                           {
                               Class = g.Key,
                               AverageScore = g.Average(s => s.Score)
                           });

foreach (var item in averageScores)
{
    Console.WriteLine($"Class {item.Class}, Average Score: {item.AverageScore}");
}

输出:

Class 1, Average Score: 81.5
Class 2, Average Score: 91
Class 3, Average Score: 88

多键分组[编辑 | 编辑源代码]

有时需要按多个属性分组。可以通过匿名类型实现多键分组。

示例:按班级和分数段分组[编辑 | 编辑源代码]

var multiKeyGroups = students.GroupBy(s => new
{
    s.Class,
    ScoreRange = s.Score >= 90 ? "High" : s.Score >= 80 ? "Medium" : "Low"
});

foreach (var group in multiKeyGroups)
{
    Console.WriteLine($"Class {group.Key.Class}, Score Range: {group.Key.ScoreRange}");
    foreach (var student in group)
    {
        Console.WriteLine($"- {student.Name}, Score: {student.Score}");
    }
}

输出:

Class 1, Score Range: Medium
- Alice, Score: 85
Class 1, Score Range: Low
- Charlie, Score: 78
Class 2, Score Range: High
- Bob, Score: 90
- David, Score: 92
Class 3, Score Range: Medium
- Eve, Score: 88

实际应用场景[编辑 | 编辑源代码]

分组操作在以下场景中非常有用: 1. 报表生成:按部门、地区或时间分组统计销售数据。 2. 数据分析:按年龄、性别或兴趣分组用户行为数据。 3. 数据清洗:将数据按某种规则分组后处理异常值。

案例:电商订单分组[编辑 | 编辑源代码]

假设有一个订单列表,需要按客户 ID 分组,并计算每个客户的总消费金额:

var orders = new List<Order>
{
    new Order { CustomerId = 1, Amount = 100 },
    new Order { CustomerId = 2, Amount = 150 },
    new Order { CustomerId = 1, Amount = 200 },
    new Order { CustomerId = 3, Amount = 50 }
};

var customerSpending = orders.GroupBy(o => o.CustomerId)
                            .Select(g => new
                            {
                                CustomerId = g.Key,
                                TotalAmount = g.Sum(o => o.Amount)
                            });

foreach (var item in customerSpending)
{
    Console.WriteLine($"Customer {item.CustomerId}, Total Spent: {item.TotalAmount}");
}

输出:

Customer 1, Total Spent: 300
Customer 2, Total Spent: 150
Customer 3, Total Spent: 50

性能注意事项[编辑 | 编辑源代码]

  • 分组操作会遍历整个集合,时间复杂度为 O(n)。
  • 对于大型数据集,可以考虑使用并行 LINQ(PLINQ)或数据库分组操作(如 SQL 的 GROUP BY)。

总结[编辑 | 编辑源代码]

LINQ 分组是一个强大的功能,能够帮助开发者高效地组织和分析数据。通过 GroupBy 方法,可以轻松实现单键或多键分组,并结合其他 LINQ 操作(如 SelectSumAverage)进行复杂的数据处理。