本篇文章给大家带来的内容是关于如何使用LINQ、Lambda 表达式 、委托快速比较两个集合,找出需要新增、修改、删除的对象(附代码),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

在工作中,经常遇到需要对比两个集合的场景,如:

  1. 页面集合数据修改,需要保存到数据库

  2. 全量同步上游数据到本系统数据库

在这些场景中,需要识别出需要新增、更新、删除的数据,由于每次应用是,需要比较的对象类型不一致,因此写了个相对通用的方法。这个过程中,需要理解的有以下2个核心概念:

  1. 唯一标识比较: 如果两个对象的唯一标识相等,则认为这两个对象在业务上代表同一个东西(次要属性是否相等暂不考虑)。

  2. 实体比较:表示两个对象在业务是不是相等(唯一标识相等、次要属性相等)。

代码示例如下:

void Main(){    // 对比源集合    var source = GenerateStudent(1, 10000, 1000);    // 目标集合    var target = GenerateStudent(5000, 10000, 1000);    // 唯一标识比较    Func<Student, Student, bool> keyCompartor = (s, t) => s.Id == t.Id;    // 实体相等比较    Func<Student, Student, bool> entityCompartor = (s, t) => s.Id == t.Id && s.Name.Equals(t.Name) && s.Age == t.Age;    // 新增前准备    Func<Student, Student> insertAction = (s) =>    {        return new Student        {            Id = s.Id,            Name = s.Name,            Age = s.Age,            Operation = "Insert"        };    };    // 更新前准备    Func<Student, Student, Student> updateAction = (s, t) =>    {        t.Name = s.Name;        t.Age = s.Age;        t.Operation = "Update";        return t;    };    // 删除前准备    Func<Student, Student> deleteAction = (t) =>    {        t.Operation = "Delete";        return t;    };    // 去掉相等对象    RemoveDuplicate(source, target, entityCompartor, (s1, s2) => s1.Id == s2.Id, keyCompartor);    // 需要新增的集合    var insertingStudents = GetInsertingEntities(source, target, keyCompartor, insertAction);    // 需要更新的集合    var updatingStudents = GetUpdatingEntities(source, target, keyCompartor, entityCompartor, updateAction);    // 需要删除的集合    var deletingStudents = GetDeletingEntities(source, target, keyCompartor, deleteAction);    // 后续业务    // InsertStudents(insertingStudents);    // UpdateStudents(updatingStudents);    // DeleteStudents(deletingStudents);}// 集合去重private void RemoveDuplicate<S, T>(List<S> source, List<T> target, Func<S, T, bool> entityCompartor,    Func<S, S, bool> sourceKeyCompartor, Func<S, T, bool> keyComportor){    var sameEntities = source.Where(s => target.Exists(t => entityCompartor(s, t))).ToList();    source.RemoveAll(s => sameEntities.Exists(s2 => sourceKeyCompartor(s, s2)));    target.RemoveAll(t => sameEntities.Exists(s => keyComportor(s, t)));}// 获取需要新增的对象集合private List<T> GetInsertingEntities<S, T>(List<S> source, List<T> target, Func<S, T, bool> keyComportor,    Func<S, T> insertAction){    var result = new List<T>();    foreach (var s in source)    {        var t = target.FirstOrDefault(x => keyComportor(s, x));        if (t == null)        {            // 目标集合中不存在,则新增            result.Add(insertAction(s));        }    }    return result;}// 获取需要更新的对象集合private List<T> GetUpdatingEntities<S, T>(List<S> source, List<T> target, Func<S, T, bool> keyComportor,    Func<S, T, bool> entityCompartor, Func<S, T, T> updateAction){    var result = new List<T>();    foreach (var s in source)    {        var t = target.FirstOrDefault(x => keyComportor(s, x));        if (t != null && !entityCompartor(s, t))        {            // 目标集合中存在,但是次要属性不相等,则更新            result.Add(updateAction(s, t));        }    }    return result;}// 获取需要删除的对象集合private List<T> GetDeletingEntities<S, T>(List<S> source, List<T> target,    Func<S, T, bool> keyComportor, Func<T, T> deleteAction){    var result = new List<T>();    foreach (var t in target)    {        var s = source.FirstOrDefault(x => keyComportor(x, t));        if (s == null)        {            // 源集合中存在,目标集合中需要删除            result.Add(deleteAction(t));        }    }    return result;}// 随机生成测试集合private List<Student> GenerateStudent(int minId, int maxId, int maxNumber){    var r = new Random();    var students = new List<Student>();    for (int i = 0; i < maxNumber; i++)    {        students.Add(new Student        {            Id = r.Next(minId, maxId),            Name = $"name: {r.Next(1, 10)}",            Age = r.Next(6, 10)        });    }    return students.GroupBy(s => s.Id).Select(s => s.First()).ToList();}public class Student{    public int Id { get; set; }    public string Name { get; set; }    public int Age { get; set; }    public string Operation { get; set; }}

例子中源集合与目标集合使用了相同的对象Student,但实际使用中,两者的类型可以不一样,只要最终返回目标集合的类型就可以了。

上面是我对集合比较的一点心得,只满足了小数据量的业务情景,并没有在大数据量的情况下做过调优。在这里也算是抛砖引玉,大家要是有更好的办法,还希望不吝赐教。

更多相关文章

  1. C++总结:面向对象的基本概念
  2. 在C++中对象如何作为参数传递和返回?(代码示例)
  3. C#学习之面向对象如何调用类以及普通方法、静态方法的使用
  4. c++是面向对象还是面向过程?
  5. 逻辑运算符两侧运算对象的数据类型是什么?
  6. golang 是面向对象的么
  7. Golang 是面向对象还是面向过程?
  8. golang是面向对象吗?
  9. Java对象的强、软、弱和虚引用

随机推荐

  1. Android之SurfaceView学习
  2. android Progressbar使用
  3. Android MediaPlayer基本使用方式
  4. Android加载中动画
  5. android 中 浏览器调用本地app应用
  6. Android(安卓)Common Use
  7. Linear Layout
  8. 6
  9. Android系统源代码情景分析:基础知识
  10. 安卓开发 - B站开源的ijkplayer播放器配