VB.net 2010 视频教程 VB.net 2010 视频教程 python基础视频教程
SQL Server 2008 视频教程 c#入门经典教程 Visual Basic从门到精通视频教程
当前位置:
首页 > 编程开发 > c#编程 >
  • LINQ高级查询——C#进行复杂数据分组与聚合

第一部分:C#基础入门
LINQ高级查询——复杂数据分组与聚合
实例介绍
在处理电商订单分析、用户行为统计等复杂数据场景时,传统的循环+字典统计方式不仅代码冗长,还容易出错。LINQ的高级查询(分组、聚合)通过声明式语法,能快速实现复杂数据统计,比如按用户分组统计消费总额、按年月分组分析销售趋势等。本节以电商订单数据分析为场景,展示LINQ在分组、聚合、嵌套分组等高级场景的应用,让你明白“为什么LINQ能vb.net教程C#教程python教程SQL教程access 2010教程
让数据处理事半功倍”。
需求分析
设计电商订单数据分析工具,核心需求如下:
1.用户消费统计:按用户分组,统计每个用户的订单总数、总消费金额、平均订单金额;
2.销售趋势分析:按年月分组,统计每月的销售总额、订单数;
3.嵌套分组统计:按用户+商品类别嵌套分组,统计每个用户在不同类别下的消费情况;
4.过滤分组结果:只显示订单数≥3的用户;
5.多条件分组:按用户+订单状态分组,统计每个用户不同状态的订单数。
代码实现

  1. 核心模型类
    csharp
	using System;
	using System.Collections.Generic;
	using System.Linq;
	
	// 用户模型
	public class User
	{
	public int Id { get; set; }
	public string Name { get; set; }
	}
	
	// 商品模型
	public class Product
	{
	public int Id { get; set; }
	public string Name { get; set; }
	public string Category { get; set; } // 商品类别:电子、服装、食品等
	public decimal Price { get; set; }
	}
	
	// 订单模型
	public class Order
	{
	public int Id { get; set; }
	public int UserId { get; set; }
	public int ProductId { get; set; }
	public int Quantity { get; set; } // 购买数量
	public DateTime OrderDate { get; set; }
	public string Status { get; set; } // 订单状态:已支付、已发货、已完成
	}
  1. 模拟数据构造
    csharp
	// 模拟数据
	public static class DataGenerator
	{
	public static List<User> GetUsers()
	{
	return new List<User>
	{
	new User { Id = 1, Name = "张三" },
	new User { Id = 2, Name = "李四" },
	new User { Id = 3, Name = "王五" }
	};
	}
	
	public static List<Product> GetProducts()
	{
	return new List<Product>
	{
	new Product { Id = 1, Name = "笔记本电脑", Category = "电子", Price = 5999.99m },
	new Product { Id = 2, Name = "T恤", Category = "服装", Price = 99.99m },
	new Product { Id = 3, Name = "牛奶", Category = "食品", Price = 59.99m },
	new Product { Id = 4, Name = "手机", Category = "电子", Price = 3999.99m }
	};
	}
	
	public static List<Order> GetOrders()
	{
	var random = new Random();
	return new List<Order>
	{
	new Order { Id = 1, UserId = 1, ProductId = 1, Quantity = 1, OrderDate = new DateTime(2024, 1, 15), Status = "已完成" },
	new Order { Id = 2, UserId = 1, ProductId = 2, Quantity = 2, OrderDate = new DateTime(2024, 1, 20), Status = "已完成" },
	new Order { Id = 3, UserId = 1, ProductId = 3, Quantity = 3, OrderDate = new DateTime(2024, 2, 5), Status = "已完成" },
	new Order { Id = 4, UserId = 2, ProductId = 4, Quantity = 1, OrderDate = new DateTime(2024, 1, 10), Status = "已完成" },
	new Order { Id = 5, UserId = 2, ProductId = 2, Quantity = 1, OrderDate = new DateTime(2024, 2, 10), Status = "已发货" },
	new Order { Id = 6, UserId = 3, ProductId = 3, Quantity = 5, OrderDate = new DateTime(2024, 1, 25), Status = "已完成" },
	new Order { Id = 7, UserId = 3, ProductId = 1, Quantity = 1, OrderDate = new DateTime(2024, 2, 15), Status = "已支付" },
	new Order { Id = 8, UserId = 3, ProductId = 4, Quantity = 1, OrderDate = new DateTime(2024, 2, 20), Status = "已完成" },
	new Order { Id = 9, UserId = 3, ProductId = 2, Quantity = 3, OrderDate = new DateTime(2024, 3, 1), Status = "已完成" }
	};
	}
	}
  1. LINQ高级查询示例
    csharp
	class Program
	{
	static void Main(string[] args)
	{
	var users = DataGenerator.GetUsers();
	var products = DataGenerator.GetProducts();
	var orders = DataGenerator.GetOrders();
	
	Console.WriteLine("=== 1. 用户消费统计(按用户分组) ===");
	// 按用户分组,统计订单数、总金额、平均金额
	var userStats = from order in orders
	join product in products on order.ProductId equals product.Id
	group new { order, product } by order.UserId into userGroup
	join user in users on userGroup.Key equals user.Id
	select new
	{
	UserName = user.Name,
	OrderCount = userGroup.Count(),
	TotalAmount = userGroup.Sum(item => item.order.Quantity * item.product.Price),
	AvgAmount = userGroup.Average(item => item.order.Quantity * item.product.Price)
	};
	foreach (var stat in userStats)
	{
	Console.WriteLine($"用户:{stat.UserName},订单数:{stat.OrderCount},总金额:{stat.TotalAmount:C},平均金额:{stat.AvgAmount:C}");
	}
	
	Console.WriteLine("
=== 2. 销售趋势分析(按年月分组) ===");
	// 按年月分组,统计销售总额、订单数
	var monthlyStats = from order in orders
	join product in products on order.ProductId equals product.Id
	group new { order, product } by new { order.OrderDate.Year, order.OrderDate.Month } into monthGroup
	select new
	{
	Year = monthGroup.Key.Year,
	Month = monthGroup.Key.Month,
	TotalSales = monthGroup.Sum(item => item.order.Quantity * item.product.Price),
	OrderCount = monthGroup.Count()
	};
	foreach (var stat in monthlyStats.OrderBy(s => s.Year).ThenBy(s => s.Month))
	{
	Console.WriteLine($"{stat.Year}年{stat.Month}月:销售总额{stat.TotalSales:C},订单数{stat.OrderCount}");
	}
	
	Console.WriteLine("
=== 3. 嵌套分组(用户+商品类别) ===");
	// 先按用户分组,再按商品类别分组
	var nestedGroup = from order in orders
	join product in products on order.ProductId equals product.Id
	group new { order, product } by order.UserId into userGroup
	join user in users on userGroup.Key equals user.Id
	select new
	{
	UserName = user.Name,
	CategoryGroups = from item in userGroup
	group item by item.product.Category into categoryGroup
	select new
	{
	Category = categoryGroup.Key,
	TotalAmount = categoryGroup.Sum(i => i.order.Quantity * i.product.Price),
	OrderCount = categoryGroup.Count()
	}
	};
	foreach (var userGroup in nestedGroup)
	{
	Console.WriteLine($"用户:{userGroup.UserName}");
	foreach (var category in userGroup.CategoryGroups)
	{
	Console.WriteLine($" 类别:{category.Category},总金额:{category.TotalAmount:C},订单数:{category.OrderCount}");
	}
	}
	
	Console.WriteLine("
=== 4. 过滤分组结果(订单数≥3的用户) ===");
	// 分组后过滤(相当于SQL的HAVING)
	var filteredUserStats = from order in orders
	join product in products on order.ProductId equals product.Id
	group new { order, product } by order.UserId into userGroup
	where userGroup.Count() >=3 // 过滤订单数≥3的分组
	join user in users on userGroup.Key equals user.Id
	select new
	{
	UserName = user.Name,
	OrderCount = userGroup.Count(),
	TotalAmount = userGroup.Sum(item => item.order.Quantity * item.product.Price)
	};
	foreach (var stat in filteredUserStats)
	{
	Console.WriteLine($"用户:{stat.UserName},订单数:{stat.OrderCount},总金额:{stat.TotalAmount:C}");
	}
	
	Console.WriteLine("
=== 5. 多条件分组(用户+订单状态) ===");
	// 按用户和订单状态分组
	var multiKeyGroup = from order in orders
	group order by new { order.UserId, order.Status } into multiGroup
	join user in users on multiGroup.Key.UserId equals user.Id
	select new
	{
	UserName = user.Name,
	Status = multiGroup.Key.Status,
	OrderCount = multiGroup.Count()
	};
	foreach (var stat in multiKeyGroup)
	{
	Console.WriteLine($"用户:{stat.UserName},状态:{stat.Status},订单数:{stat.OrderCount}");
	}
	}
	}

逐行讲解

  1. 用户消费统计
    join操作:关联订单和商品表,获取商品价格;
    group by order.UserId:按用户ID分组,将订单和商品的联合数据分组到userGroup;
    join user:关联用户表,获取用户名;
    聚合函数:Count()统计订单数,Sum()计算总金额,Average()计算平均金额;
    匿名类型:用匿名类型存储结果,简化代码。
  2. 销售趋势分析
    多键分组:用new { Year, Month }作为分组键,实现按年月分组;
    OrderBy/ThenBy:对结果按年月排序,使输出更直观;
    Sum/Count:统计每月销售总额和订单数。
  3. 嵌套分组
    两层分组:先按用户分组,再在用户分组内按商品类别分组;
    CategoryGroups:内层分组结果,存储每个用户下不同类别的消费数据;
    嵌套遍历:外层遍历用户,内层遍历类别,输出详细统计。
  4. 过滤分组结果
    where子句:在分组后使用where,过滤出订单数≥3的用户(相当于SQL的HAVING子句);
    执行顺序:先分组,再过滤,最后关联用户表获取用户名。
  5. 多条件分组
    多键匿名类型:用new { UserId, Status }作为分组键,实现按用户和订单状态双重分组;
    统计结果:显示每个用户不同状态的订单数,帮助分析订单处理情况。
    基础知识拓展
  6. LINQ分组的核心概念
    IGrouping<TKey, TElement>:分组结果的类型,包含Key(分组键)和实现IEnumerable(分组内的元素);
    延迟执行:LINQ查询在遍历结果时才执行,若数据变化,结果会随之变化;
    匿名类型:用于多键分组或存储临时结果,编译器自动生成类,属性只读。
  7. LINQ分组与SQL分组的区别
    特性 LINQ分组 SQL分组
    分组结果 保留分组内所有元素 只保留分组键和聚合结果
    多键分组 用匿名类型 用逗号分隔多个列
    嵌套分组 支持多层分组 需用子查询或CTE
    过滤时机 分组前(where)或分组后(where) 分组前(WHERE)或分组后(HAVING)
  8. 性能优化技巧
    提前过滤:在分组前用where过滤不需要的数据,减少分组的数据量;
    避免重复关联:若多次关联同一表,可先关联再分组;
    使用索引:若数据来自数据库,确保分组键列有索引,提高查询速度;
    ToList()/ToArray():若需多次使用分组结果,用ToList()缓存结果,避免重复执行查询。
  9. 常见聚合函数
    Count():统计元素数量;
    Sum():计算数值型元素的总和;
    Average():计算数值型元素的平均值;
    Max()/Min():获取元素的最大值/最小值;
    First()/Last():获取分组内第一个/最后一个元素。
    总结
    LINQ高级查询通过分组、聚合、嵌套分组等功能,能快速处理复杂数据统计任务,代码简洁易读,比传统循环方式效率更高。掌握LINQ高级查询,能大幅提升数据处理能力,尤其在数据分析、报表生成等场景中应用广泛。核心要点:
    用group by实现分组,into关键字保存分组结果;
    多键分组用匿名类型,嵌套分组用内层查询;
    聚合函数用于统计分组数据,where子句可过滤分组结果;
    延迟执行需注意数据变化对结果的影响。
    通过本节学习,你可以将LINQ高级查询应用到实际项目中,提高代码质量和开发效率。

 本站原创,转载请注明出处:https://www.xin3721.com/ArticlecSharp/c49428.html


相关教程