집 >백엔드 개발 >C#.Net 튜토리얼 >LINQ, Lambda 식 및 대리자를 사용하여 두 컬렉션을 빠르게 비교하고 추가, 수정 또는 삭제해야 하는 개체를 찾는 방법(코드 첨부)
이 문서의 내용은 LINQ, Lambda 식 및 대리자를 사용하여 두 컬렉션을 빠르게 비교하고 (코드 포함) 추가, 수정 및 삭제해야 하는 개체를 찾는 방법에 대한 것입니다. 도움이 필요한 친구들이 참고하면 도움이 되리라 믿습니다.
직장에서 우리는 다음과 같이 두 컬렉션을 비교해야 하는 시나리오에 자주 직면합니다.
페이지 컬렉션 데이터 수정 사항을 데이터베이스에 저장해야 함
업스트림 데이터를 이 시스템 데이터베이스에 완전히 동기화
이러한 시나리오에서는 추가, 업데이트, 삭제해야 할 데이터를 식별해야 합니다. 각 애플리케이션마다 비교해야 하는 개체 유형이 일치하지 않기 때문에 비교적 일반적인 방법을 작성했습니다. 이 과정에서 다음 두 가지 핵심 개념을 이해해야 합니다.
고유 ID 비교: 두 객체의 고유 ID가 동일하면 두 객체는 비즈니스에서 동일한 것을 나타내는 것으로 간주됩니다(보조 속성인지 여부) 현재로서는 동등하다는 점을 고려하지 않습니다.)
엔티티 비교: 비즈니스에서 두 객체가 동일한지 여부를 나타냅니다(고유 식별자가 동일하고 보조 속성이 동일함).
코드 예시는 다음과 같습니다.
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
. 그러나 실제 사용에서는 두 유형이 서로 다를 수 있습니다. 결국 대상 컬렉션이 반환됩니다.
위 내용은 컬렉션 비교에 대한 내 경험입니다. 이는 데이터 용량이 작은 비즈니스 시나리오에만 부합하며 데이터 용량이 큰 경우에는 최적화되지 않았습니다. 이것이 출발점이라고 볼 수 있습니다. 더 좋은 방법이 있다면 조언을 해주셨으면 좋겠습니다.
위 내용은 LINQ, Lambda 식 및 대리자를 사용하여 두 컬렉션을 빠르게 비교하고 추가, 수정 또는 삭제해야 하는 개체를 찾는 방법(코드 첨부)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!