.NET的求复杂类型集合的差集、交集、并集

前言

如标题所述,在ASP.NET应用程序开发中,两个集合做比较时 我们使用微软IEnumerable封装的 Except/Intersect/Union 取 差集/交集/并集 方法是非常的方便的;

但以上对于不太熟悉的小伙伴来讲,在遇到求包含引用类型(不包含string)集合时就非常的苦恼;

下面我将带着大家去了解如何通过微软自带方法方式去取**复杂类型集合**的差集、交集、并集。

 

场景

这里是场景,我有以下两个学生集合。

namespace Test2 {     internal class Program     {         public void Main()         {             //列表1             List<Student> StudentList1 = new List<Student>()             {                   new Student {Id=1,Name="小明",Age=27  },                   new Student {Id=3,Name="大郭",Age=28  },                   new Student {Id=4,Name="老登",Age=29  }              };             List<Student> StudentList2 = new List<Student>()             {                  new Student {Id=1,Name="小明",Age=27  },                  new Student {Id=3,Name="大郭",Age=28  },                  new Student {Id=4,Name="老登",Age=29 },                  new Student {Id=4,Name="小路",Age=28 },                  new Student {Id=4,Name="小明",Age=30 }              };          }     } }

 

 生成两个实体集合;

 

下面我们取交集/差集/并集

 

完整调用示例(.NET Core):

namespace Test2 {     internal class Program     {         public static void Main()         {             //列表1             List<Student> StudentList1 = new List<Student>()             {                   new Student {Id=1,Name="小明",Age=27  },                   new Student {Id=2,Name="大郭",Age=28  },                   new Student {Id=3,Name="老登",Age=29  }              };             //列表2             List<Student> StudentList2 = new List<Student>()             {                  new Student {Id=1,Name="小明",Age=27  },                  new Student {Id=2,Name="大郭",Age=28  },                  new Student {Id=3,Name="老登",Age=29 },                  new Student {Id=4,Name="小路",Age=28 },                  new Student {Id=5,Name="小明",Age=30 }               };             //取比列表1里多出来的学生数据 并输出             var ExceptData = StudentList2.Except(StudentList1);             Console.WriteLine("差集:" + String.Join(";", ExceptData.Select(x => { return $"{x.Id}-{x.Name}-{x.Age}"; })));              //取列表1与列表2里共有的学生数据             var IntersectData = StudentList1.Intersect(StudentList2);             Console.WriteLine("交集:" + String.Join(";", IntersectData.Select(x => { return $"{x.Id}-{x.Name}-{x.Age}"; })));              //获取办理所有学生的数据(一个相同的学生只能一条)             var UnionData = StudentList1.Union(StudentList2);             Console.WriteLine("并集:"+String.Join(";", UnionData.Select(x => { return $"{x.Id}-{x.Name}-{x.Age}"; })));          }      } }

 输出:

  差集:1-小明-27;2-大郭-28;3-老登-29;4-小路-28;5-小明-30
  交集:null
  并集:1-小明-27;2-大郭-28;3-老登-29;1-小明-27;2-大郭-28;3-老登-29;4-小路-28;5-小明-30

以上输出仔细看一下明显是不对的,这就涉及到了复杂类型对比,请看代码:

正常我们声明的类

/// <summary> /// 学生类 /// </summary> internal class Student {     /// <summary>     /// 编号     /// </summary>     public int Id { get; set; }      /// <summary>     /// 姓名     /// </summary>     public string Name { get; set; }      /// <summary>     /// 年龄     /// </summary>     public int Age { get; set; }  }

 

 因为我们要对比的是引用类型,因为在对比除string引用类型外,其他引用类型的对比默认都是对比的堆里地址,所以我们要实现一个自定义的对比方案

我们需要继承一个接口 IEqualityComparer<T> 泛型接口

如下:(这里我们以年龄与名做为对比条件)

/// <summary> /// 学生类 /// </summary> internal class Student : IEqualityComparer<Student> {     /// <summary>     /// 编号     /// </summary>     public int Id { get; set; }      /// <summary>     /// 姓名     /// </summary>     public string Name { get; set; }      /// <summary>     /// 年龄     /// </summary>     public int Age { get; set; }      /// <summary>     /// 比较器     /// </summary>     /// <param name="s1">比较实体1</param>     /// <param name="s2">比较实体2</param>     /// <returns></returns>     public bool Equals(Student s1, Student s2)     {         //验证相等条件         if (s1.Name == s2.Name && s1.Age == s2.Age)         {             return true;         }         return false;     }      /// <summary>     /// 获取唯一条件     /// </summary>     /// <param name="stu"></param>     /// <returns></returns>     public int GetHashCode(Student stu)     {         return (stu.Name + "|" + stu.Age).GetHashCode();     } }

 

修改了类后还有最重要的一点:就是修改比较的方法(相当于声明一个自定义的比较器给方法)

   //取比列表1里多出来的学生数据 并输出             var ExceptData = StudentList2.Except(StudentList1,new Student());             Console.WriteLine("差集:" + String.Join(";", ExceptData.Select(x => { return $"{x.Id}-{x.Name}-{x.Age}"; })));              //取列表1与列表2里共有的学生数据             var IntersectData = StudentList1.Intersect(StudentList2,new Student());             Console.WriteLine("交集:" + String.Join(";", IntersectData.Select(x => { return $"{x.Id}-{x.Name}-{x.Age}"; })));              //获取办理所有学生的数据(一个相同的学生只能一条)             var UnionData = StudentList1.Union(StudentList2,new Student());             Console.WriteLine("并集:"+String.Join(";", UnionData.Select(x => { return $"{x.Id}-{x.Name}-{x.Age}"; })));

 输出:

  差集:4-小路-28;5-小明-30 

  交集:1-小明-27;2-大郭-28;3-老登-29

  并集:1-小明-27;2-大郭-28;3-老登-29;4-小路-28;5-小明-30

 

到这里引用类型的比较已经完成了,比较器的条件方法可以根据需求调整,如有不足之处,希望大家多多指正!!!

 

 
 
 
 
 
 
 
 

发表评论

相关文章