C#的GroupBy方法是如何工作的
前言:先贴结果
GroupBy方法是如何工作的?
一、准备6个待分组的学生对象
class student { public string name;//姓名 public int grade;//年级 public student(string name, int grade) { this.name = name; this.grade = grade; } }
List<student> students = new List<student>(); for (int i = 0; i < 3; i++) { students.Add(new student("学生" + i, 1)); } for (int i = 0; i < 3; i++) { students.Add(new student("学生" + (i+3), 2)); }
其中有3个1年级,3个2年级
二、准备分组比较值产生器
static int getGrade(student stu) { Console.WriteLine("分组关键字->\t该学生的年级:" + stu.grade); return stu.grade; }
分组方法将会调用此方法,得到分组依据
三、准备分组比较器
//学生年级相等比较器,如果分组关键字使用了学生对象,那么这里就可以用学生的其他属性进行相等比较,比如学生ID class studentComparer : IEqualityComparer<int> { //判断关键字是否相等,当然也可以是大于,平方,等任意规则 public bool Equals(int x, int y) { if (x==y) { Console.WriteLine("比较器->\t学生年级相等:" + x + "年级"); return true; } else { Console.WriteLine("学生年级不相等"); return false; } } public int GetHashCode(int x) { int code = x.GetHashCode(); return code.GetHashCode(); } }
分组比较器将会对分组关键字进行比较,得到分组
四、GroupBy()分组器
//给GroupBy传入分组方法,ToList()执行分组时,程序对元素集中的每个元素调用"相等比较器"进行分组 //得到一个包含几个分组对象IGrouping的枚举对象IEnumerable //每个分组对象IGrouping的属性是:(分组键值,分组元素集) //因此GroupBy方法属于js中的高级方法,就像map,reduce等 //可以自定义"相等比较器"IEqualityComparer,自定义相等判断规则 IEnumerable<IGrouping<int,student>> d = students.GroupBy<student, int>(getGrade,new studentComparer()).ToList();
分组器将会采用一个尽可能减少比较次数的算法,使用比较器对分组关键字比较
在这个例子中,6个学生分两组只进行了4次比较,第一直觉是应该会用5次比较
五、分组结果展示
foreach (IGrouping<int,student> item in d) { Console.WriteLine(item.Key+"年级:"); foreach (student stu in item) { Console.WriteLine("\t名字:" + stu.name); } } Console.WriteLine("系统的比较方法很厉害,只用4次比较,将6个元素分成了2组,采用2分法的方式似乎可以"); Console.ReadLine();
六、完整代码
class Program { static void Main(string[] args) { //6个学生 List<student> students = new List<student>(); for (int i = 0; i < 3; i++) { students.Add(new student("学生" + i, 1)); } for (int i = 0; i < 3; i++) { students.Add(new student("学生" + (i+3), 2)); } //var d = students.GroupBy<student,int>(t => t.grade);//对studentList按照ClassCode分组 //给GroupBy传入分组方法,ToList()执行分组时,程序对元素集中的每个元素调用"相等比较器"进行分组 //得到一个包含几个分组对象IGrouping的枚举对象IEnumerable //每个分组对象IGrouping的属性是:(分组键值,分组元素集) //因此GroupBy方法属于js中的高级方法,就像map,reduce等 //可以自定义"相等比较器"IEqualityComparer,自定义相等判断规则 IEnumerable<IGrouping<int,student>> d = students.GroupBy<student, int>(getGrade,new studentComparer()).ToList(); foreach (IGrouping<int,student> item in d) { Console.WriteLine(item.Key+"年级:"); foreach (student stu in item) { Console.WriteLine("\t名字:" + stu.name); } } Console.WriteLine("系统的比较方法很厉害,只用4次比较,将6个元素分成了2组,采用2分法的方式似乎可以"); Console.ReadLine(); } static int getGrade(student stu) { Console.WriteLine("分组关键字->\t该学生的年级:" + stu.grade); return stu.grade; } } class student { public string name;//姓名 public int grade;//年级 public student(string name, int grade) { this.name = name; this.grade = grade; } } //学生年级相等比较器,如果分组关键字使用了学生对象,那么这里就可以用学生的其他属性进行相等比较,比如学生ID class studentComparer : IEqualityComparer<int> { public bool Equals(int x, int y) { if (x==y) { Console.WriteLine("比较器->\t学生年级相等:" + x + "年级"); return true; } else { Console.WriteLine("学生年级不相等"); return false; } } public int GetHashCode(int x) { int code = x.GetHashCode(); return code.GetHashCode(); } }