第一部分内容可以直接在控制台程序输出
目录
一、基础分组处理
class MainClass
{
static List<Student> StudentList = new List<Student>()
{
new Student(){ Id=1,Name="小明",Classes="201班",Sex="男",Score=90},
new Student(){ Id=2,Name="小虹",Classes="201班",Sex="女",Score=99},
new Student(){ Id=3,Name="小二",Classes="202班",Sex="男",Score=60},
new Student(){ Id=4,Name="小宫",Classes="202班",Sex="男",Score=50},
new Student(){ Id=5,Name="小蓝",Classes="202班",Sex="女",Score=60},
new Student(){ Id=6,Name="小力",Classes="202班",Sex="男",Score=70},
new Student(){ Id=7,Name="小梅",Classes="202班",Sex="女",Score=90},
new Student(){ Id=8,Name="小萱",Classes="203班",Sex="女",Score=20}
};
static void Main(string[] args)
{
//1.查询有多少个不一样的班级(去重)
List<string> list1 = StudentList.Select(x => x.Classes).Distinct().ToList();
//List<string> list2 = StudentList.Select(x => x.Classes).ToHashSet().ToList();//也可以这样写
//【分组结构分析(以2为例)】:201班、202班、203班分别有一个列表,s是分组依据、g是组长列表,x是组员实体
IEnumerable<IGrouping<string, Student>> temp = StudentList.GroupBy(s => s.Classes);//temp=三个列表
// 2.每个班为一组,统计出每个班的总分
var list2 = StudentList.GroupBy(s => s.Classes).Select(g => new { Class = g.Key, TotalScore = g.Sum(x => x.Score) }).ToList();
Console.WriteLine(string.Join("\n", list2));
// 3.每个班、每个性别为一组,统计出每个班、每个性别的总分
var list3 = StudentList.GroupBy(s => new { s.Classes, s.Sex }).Select(g => new { Class = g.Key.Classes, Gender = g.Key.Sex, TotalScore = g.Sum(x => x.Score) }).ToList();
Console.WriteLine(string.Join("\n", list3));
//4.每个班、每个性别为一组,统计出每个班、每个性别的Score小于60的数量以及它们的姓名、代表姓名、该班该性别下学生的所有姓名
var list4 = StudentList.GroupBy(s => new { s.Classes, s.Sex })
.Select(g => new
{
Class = g.Key.Classes,
Gender = g.Key.Sex,
Count = g.Count(x => x.Score < 60),//该班该性别不及格的数量
Names = string.Join(", ", g.Where(x => x.Score < 60).Select(x => x.Name)),//该班该性别不及格的姓名
Names2 = g.FirstOrDefault()?.Name,//学生代表,列表第一位
Names3 = g.Select(x=>x.Name)//该班该性别下学生的所有姓名(返回的是list)
});
Console.WriteLine(string.Join("\n", list4));
}
}
class Student
{
public int Id;
public string Name;
public string Classes;
public string Sex;
public int Score;
}
二、含列表分组处理
【数据库查表数据】ProjectID,Price,Stamonths=[time,Money]
项目名 | 项目金额 | 1月成本 | 2月成本 |
项目1 | 200 | 100 | 200 |
项目1 | 100 | 50 | 60 |
项目2 | 1000 | 30 | 80 |
项目2 | 300 | 100 | 40 |
项目3 | 1500 | 80 | 60 |
分组前——list
项目1 项目金额 [月份1金额 月份2金额](List<Stamonths>)
项目1 项目金额 [月份1金额 月份2金额]
项目2 项目金额 [月份1金额 月份2金额]
项目2 项目金额 [月份1金额 月份2金额]
项目3 项目金额 [月份1金额 月份2金额]
【前端展现页面】
项目名 | 项目金额 | 1月成本 | 2月成本 |
项目1 | 300 | 150 | 260 |
项目1 | 200 | 100 | 200 |
项目1 | 100 | 50 | 60 |
项目2 | 1300 | 130 | 120 |
项目2 | 1000 | 30 | 80 |
项目2 | 300 | 100 | 40 |
项目3 | 1500 | 80 | 60 |
项目3 | 1500 | 80 | 60 |
【说明】
1.粉色是父节点,其他为子节点
2.代码中g是加粗部分,s是非加粗部分
分组后——result_list(缩进代表是Children下的数据)
项目1 项目总金额 [月份1总金额 月份总2金额](List<Stamonths>)
项目1 项目金额 [月份1金额 月份2金额]
项目1 项目金额 [月份1金额 月份2金额]
项目2 项目总金额 [月份1总金额 月份总2金额]
项目2 项目金额 [月份1金额 月份2金额]
项目2 项目金额 [月份1金额 月份2金额]
项目3 项目总金额 [月份1总金额 月份总2金额]
项目3 项目金额 [月份1金额 月份2金额]
代码:
var result_list = list.GroupBy(s => new { s.ProjectID })
.Select(g => new
{
ProjectID = g.Key.ProjectID,//组别,即项目ID
TotalPrice = g.Sum(s => s.Price),//汇总数据:处理项目总金额,实现对Children的各项目金额相加
Stamonths = g.SelectMany(s => s.Stamonths)//汇总数据:拿出列表分组=》实现对Children的列表金额相加
.GroupBy(s => s.Time)
.Select(s => new
{
time = s.Key,
Money = s.Sum(x => x.Money)
})
.ToList(),
Children=g.Select(s => new//列出子数据
{
s.ProjectID,
s.Price,
Stamonths = s.Stamonths
})
})
.ToList();
三、多组别分组处理(复杂,一般很少用)
【数据库查表数据】
小组(负责人) | 产品名称 | 产品经理 | 产品批次 | 产品成本 | 售出批次 | 销售价格 | 销售日期 |
医疗组(xiaoxiao) | 专专产品 | 新测试员2023 | 产品批次1 | 200 | 默认批次 | 10000 | 2022/1/1 |
医疗组(xiaoxiao) | 专专产品 | 新测试员2023 | 产品批次2 | 100 | 默认批次 | 10000 | 2022/1/1 |
医疗组(xiaoxiao) | 专专产品 | 新测试员2023 | 产品批次1 | 200 | 批次2 | 3000 | 2022/1/2 |
医疗组(xiaoxiao) | 专专产品 | 新测试员2023 | 产品批次2 | 100 | 批次2 | 3000 | 2022/1/2 |
医疗组(xiaoxiao) | 专专产品 | 新测试员2023 | 产品批次1 | 200 | 批次3 | 1500 | NULL |
医疗组(xiaoxiao) | 专专产品 | 新测试员2023 | 产品批次2 | 100 | 批次3 | 1500 | NULL |
【前端展现页面】
小组(负责人) | 产品名称 | 产品经理 | 产品批次 | 产品成本 | 销售总收入 | 售出批次 | 销售价格 | 销售日期 |
医疗组(xiaoxiao) | 专专产品 | 新测试员2023 | 产品批次1 | 200 | 14500 | 默认批次 | 10000 | 2022/1/1 |
批次2 | 3000 | 2022/1/2 | ||||||
产品批次2 | 100 | 批次3 | 1500 | NULL |
小组:产品:产品经理=1:1:1; 产品:产品批次=1:n ; 产品:售出批次=1:n ;产品批次和售出批次无直接对应关系;颜色说明了它们之间的对应关系。
【期望返回数据格式】
[
{
"GroupName": "医疗组",
"Leader": "xiaoxiao",
"productName": "专专产品",
"productManager": "新测试员2023",
"productSumIncome": 300,
"productDetails": [
{
"productBatchesName": "产品批次1",
"projectCost": 200
},
{
"productBatchesName": "产品批次2",
"projectCost": 100
}
],
"salesDetails": [
{
"salesBatchsName": "批次3",
"settleTime": null,
"salesPrice": 1500
},
{
"salesBatchsName": "默认批次",
"settleTime": null,
"salesPrice": 10000
},
{
"salesBatchsName": "批次2",
"settleTime": null,
"salesPrice": 3000
}
]
}
]
【代码编写策略】先分组,后筛选
var resultlist = product_list.GroupBy(d => new
{//不同组名、不同负责人、不同产品、不同产品经理为一组
d.GroupName,
d.LeaderName,
d.ProductName,
d.ProjectManager
})
.Select(g => new
{//筛选出我要的内容
Name = g.Key.GroupName,//组别
Leader = g.Key.LeaderName,
ProductName = g.Key.ProductName,
ProductManager = g.Key.ProjectManager,
ProductSumIncome = g.GroupBy(x => x.SalesBatchsName).Sum(x=>x.FirstOrDefault()?.ProductIncome),//小组信息汇总,即【Flag】处加和,代表销售总收入
ProductDetails = g.GroupBy(x => x.ProBatchesName).Select(//小组信息展示(产品分组,对应蓝色框框)
s => new
{
ProductBatchesName = s.Key,//组别,即ProBatchesName(产品批次名)
ProjectCost = s.FirstOrDefault()?.ProjectCost//小组成员对应的信息
}),
SalesDetails = g.GroupBy(x => x.SalesBatchsName).Select(s => new//小组信息展示(销售分组,对应粉色框框)
{
SalesBatchsName = s.Key,//组别,即BatchesName(销售批次名)
SettleTime = s.FirstOrDefault()?.SettleTime,
SalesPrice = s.FirstOrDefault()?.ProductIncome//【Flag】
})
}) ;
四、基础去重处理
(1)程序写法
class MainClass
{
static List<Product> ProductList = new List<Product>()
{
new Product(){ Id=1,Name="产品1号",CustormuerName="李老板",Batches="批次1"},
new Product(){ Id=1,Name="产品1号",CustormuerName="王老板",Batches="批次1"},
new Product(){ Id=1,Name="产品1号",CustormuerName="王老板",Batches="批次1"},
new Product(){ Id=1,Name="产品1号",CustormuerName="李老板",Batches="批次2"},
new Product(){ Id=2,Name="产品2号",CustormuerName="苏老板",Batches="批次1"},
new Product(){ Id=2,Name="产品2号",CustormuerName="李老板",Batches="批次1"}
};
static void Main(string[] args)
{
//(1)数据一样的去重
var list1_1 = ProductList
.GroupBy(p => new { p.Id, p.Name, p.CustormuerName, p.Batches })
.Select(g => g.First())
.ToList();
//(2)产品名字一样的去重,返回第一条
var list1_2 = ProductList.DistinctBy(x => x.Name).ToList();
//(3)产品名字和客户名字一样的去重,返回第一条
var list1_3 = ProductList.DistinctBy(x => new
{
x.Name, x.CustormuerName
}).ToList();
}
}
class Product
{
public int Id;
public string Name;
public string CustormuerName;
public string Batches;
}
(2)SQL写法
--(1)内容一样去重,返回第一条
SELECT Name, CustormuerName, Batches, Income
FROM ProductTable
GROUP BY Name, CustormuerName, Batches, Income
--(2)产品名字一样的去重,返回第一条
SELECT Name
FROM ProductTable
GROUP BY Name
--(3)产品名字和客户名字一样的去重,返回第一条
SELECT Name, CustormuerName
FROM ProductTable
GROUP BY Name, CustormuerName
【SQL分组注意】
1.GROUP BY 字段要和SELECT字段一致
2.聚合函数使用:MAX可以取分组后的第一个代表元素,COUNT(*)可以表示分组之后该小组有多少条数据,AVG,SUM等函数是计算小组某个字段的平均值和总和的。
3.如果想取小组中的指定序号的成员,需要用ROW_NUMBER()关键字处理。
五、一些小结
1.初始化区别
- new List<object>(resultlist):将 resultlist 中的元素逐个复制到新的列表中。
- new List<object>{resultlist}:将 resultlist 作为单个元素添加到新的列表中。
- 第一种结构就是List<object>,即 ["item1", "item2", "item3"]
- 第二种结构是List<object>下带有resullist,即 [{"resultlist": ["item1", "item2", "item3"]}]
2.列表初始化注意的点
- 需要写两个new
//【字段】
public class ProjectIncomeResult
{
public decimal TotalPriceSum { get; set; }
public List<MonthlyIncomSums> MonthlyIncomeSumList { get; set; }
}
//【写法】
var resultlist = new List<ProjectIncomeResult> {
new ProjectIncomeResult
{
TotalPriceSum=10000,
MonthlyIncomeSumList = monthlyIncomeSums
}
};
-
封装的写法(result是已写好的结构)
var resultlist = new List<ProductResult> (result)
3.如何将Object转为实体
【步骤】:
第一步,照着object类写实体字段。(也可以叫AI写)
第二步,在object类的【Select】里面的【new】后面加上具体的实体类
第三步,在object类的屁股后加【.ToList()】
【原来的object类】
var resultlist = product_list.GroupBy(d => new
{
d.AmoebaName,
d.AmoebaLeaderName,
})
.Select(g => new
{
AmoebaName = g.Key.AmoebaName,
AmoebaLeader = g.Key.AmoebaLeaderName,
ProductSumCost = g.GroupBy(x=>x.ProBatchesName).Sum(x=>x.FirstOrDefault()?.ProjectCost),
ProductSumIncome = g.GroupBy(x => x.BatchsName).Sum(x=>x.FirstOrDefault()?.ProductIncome),
SalesDetails = g.GroupBy(x => x.BatchsName).Select(s => new
{
SalesBatchsName = s.Key,
SettleTime = s.FirstOrDefault()?.SettleTime,
SalesPrice = s.FirstOrDefault()?.ProductIncome
})
});
【第一步,写字段】
public class ProductResult
{
public string AmoebaName { get; set; }
public string AmoebaLeader { get; set; }
public double? ProductSumCost { get; set; }
public double? ProductSumIncome { get; set; }
public IEnumerable<SalesDetail> SalesDetails { get; set; }//实体下面有集合
}
public class SalesDetail
{
public string SalesBatchsName { get; set; }
public DateTime? SettleTime { get; set; }
public double? SalesPrice { get; set; }
}
【第二三步,加具体实体和加Tolist()】
var resultlist = product_list.GroupBy(d => new
{
d.AmoebaName,
d.AmoebaLeaderName,
})
.Select(g => new ProductResult
{
AmoebaName = g.Key.AmoebaName,
AmoebaLeader = g.Key.AmoebaLeaderName,
ProductSumCost = g.GroupBy(x=>x.ProBatchesName).Sum(x=>x.FirstOrDefault()?.ProjectCost),
ProductSumIncome = g.GroupBy(x => x.BatchsName).Sum(x=>x.FirstOrDefault()?.ProductIncome),
SalesDetails = g.GroupBy(x => x.BatchsName).Select(s => new SalesDetail
{
SalesBatchsName = s.Key,
SettleTime = s.FirstOrDefault()?.SettleTime,
SalesPrice = s.FirstOrDefault()?.ProductIncome
})
}).ToList() ;
【注意】实体类需用等于号赋值,不能省略
result.ReturnData = new ManPowAllResult
{
resultlist=resultlist,
allSumlist=allSumlist
};