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

打印 上一主题 下一主题

主题 876|帖子 876|积分 2628

前言

如标题所述,在ASP.NET应用程序开发中,两个集合做比较时 我们使用微软IEnumerable封装的 Except/Intersect/Union 取 差集/交集/并集 方法是非常的方便的;
但以上对于不太熟悉的小伙伴来讲,在遇到求包含引用类型(不包含string)集合时就非常的苦恼;
下面我将带着大家去了解如何通过微软自带方法方式去取**复杂类型集合**的差集、交集、并集。
 
场景

这里是场景,我有以下两个学生集合。
  1. namespace Test2
  2. {
  3.     internal class Program
  4.     {
  5.         public void Main()
  6.         {
  7.             //列表1
  8.             List<Student> StudentList1 = new List<Student>()
  9.             {
  10.                   new Student {Id=1,Name="小明",Age=27  },
  11.                   new Student {Id=3,Name="大郭",Age=28  },
  12.                   new Student {Id=4,Name="老登",Age=29  }
  13.              };
  14.             List<Student> StudentList2 = new List<Student>()
  15.             {
  16.                  new Student {Id=1,Name="小明",Age=27  },
  17.                  new Student {Id=3,Name="大郭",Age=28  },
  18.                  new Student {Id=4,Name="老登",Age=29 },
  19.                  new Student {Id=4,Name="小路",Age=28 },
  20.                  new Student {Id=4,Name="小明",Age=30 }
  21.              };
  22.         }
  23.     }
  24. }
复制代码
 
 生成两个实体集合;
 
下面我们取交集/差集/并集

 完整调用示例(.NET Core):
  1. namespace Test2
  2. {
  3.     internal class Program
  4.     {
  5.         public static void Main()
  6.         {
  7.             //列表1
  8.             List<Student> StudentList1 = new List<Student>()
  9.             {
  10.                   new Student {Id=1,Name="小明",Age=27  },
  11.                   new Student {Id=2,Name="大郭",Age=28  },
  12.                   new Student {Id=3,Name="老登",Age=29  }
  13.              };
  14.             //列表2
  15.             List<Student> StudentList2 = new List<Student>()
  16.             {
  17.                  new Student {Id=1,Name="小明",Age=27  },
  18.                  new Student {Id=2,Name="大郭",Age=28  },
  19.                  new Student {Id=3,Name="老登",Age=29 },
  20.                  new Student {Id=4,Name="小路",Age=28 },
  21.                  new Student {Id=5,Name="小明",Age=30 }
  22.              };
  23.             //取比列表1里多出来的学生数据 并输出
  24.             var ExceptData = StudentList2.Except(StudentList1);
  25.             Console.WriteLine("差集:" + String.Join(";", ExceptData.Select(x => { return $"{x.Id}-{x.Name}-{x.Age}"; })));
  26.             //取列表1与列表2里共有的学生数据
  27.             var IntersectData = StudentList1.Intersect(StudentList2);
  28.             Console.WriteLine("交集:" + String.Join(";", IntersectData.Select(x => { return $"{x.Id}-{x.Name}-{x.Age}"; })));
  29.             //获取办理所有学生的数据(一个相同的学生只能一条)
  30.             var UnionData = StudentList1.Union(StudentList2);
  31.             Console.WriteLine("并集:"+String.Join(";", UnionData.Select(x => { return $"{x.Id}-{x.Name}-{x.Age}"; })));
  32.         }
  33.     }
  34. }
复制代码
 输出:
  差集: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
以上输出仔细看一下明显是不对的,这就涉及到了复杂类型对比,请看代码:

正常我们声明的类
  1. /// <summary>
  2. /// 学生类
  3. /// </summary>
  4. internal class Student
  5. {
  6.     /// <summary>
  7.     /// 编号
  8.     /// </summary>
  9.     public int Id { get; set; }
  10.     /// <summary>
  11.     /// 姓名
  12.     /// </summary>
  13.     public string Name { get; set; }
  14.     /// <summary>
  15.     /// 年龄
  16.     /// </summary>
  17.     public int Age { get; set; }
  18. }
复制代码
 
 因为我们要对比的是引用类型,因为在对比除string引用类型外,其他引用类型的对比默认都是对比的堆里地址,所以我们要实现一个自定义的对比方案
我们需要继承一个接口 IEqualityComparer 泛型接口
如下:(这里我们以年龄与名做为对比条件)
  1. /// <summary>
  2. /// 学生类
  3. /// </summary>
  4. internal class Student : IEqualityComparer<Student>
  5. {
  6.     /// <summary>
  7.     /// 编号
  8.     /// </summary>
  9.     public int Id { get; set; }
  10.     /// <summary>
  11.     /// 姓名
  12.     /// </summary>
  13.     public string Name { get; set; }
  14.     /// <summary>
  15.     /// 年龄
  16.     /// </summary>
  17.     public int Age { get; set; }
  18.     /// <summary>
  19.     /// 比较器
  20.     /// </summary>
  21.     /// <param name="s1">比较实体1</param>
  22.     /// <param name="s2">比较实体2</param>
  23.     /// <returns></returns>
  24.     public bool Equals(Student s1, Student s2)
  25.     {
  26.         //验证相等条件
  27.         if (s1.Name == s2.Name && s1.Age == s2.Age)
  28.         {
  29.             return true;
  30.         }
  31.         return false;
  32.     }
  33.     /// <summary>
  34.     /// 获取唯一条件
  35.     /// </summary>
  36.     /// <param name="stu"></param>
  37.     /// <returns></returns>
  38.     public int GetHashCode(Student stu)
  39.     {
  40.         return (stu.Name + "|" + stu.Age).GetHashCode();
  41.     }
  42. }
复制代码
 
修改了类后还有最重要的一点:就是修改比较的方法(相当于声明一个自定义的比较器给方法)
  1.    //取比列表1里多出来的学生数据 并输出
  2.             var ExceptData = StudentList2.Except(StudentList1,new Student());
  3.             Console.WriteLine("差集:" + String.Join(";", ExceptData.Select(x => { return $"{x.Id}-{x.Name}-{x.Age}"; })));
  4.             //取列表1与列表2里共有的学生数据
  5.             var IntersectData = StudentList1.Intersect(StudentList2,new Student());
  6.             Console.WriteLine("交集:" + String.Join(";", IntersectData.Select(x => { return $"{x.Id}-{x.Name}-{x.Age}"; })));
  7.             //获取办理所有学生的数据(一个相同的学生只能一条)
  8.             var UnionData = StudentList1.Union(StudentList2,new Student());
  9.             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
 
到这里引用类型的比较已经完成了,比较器的条件方法可以根据需求调整,如有不足之处,希望大家多多指正!!!
 
        
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

欢乐狗

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表