>  기사  >  백엔드 개발  >  LINQ, Lambda 식 및 대리자를 사용하여 두 컬렉션을 빠르게 비교하고 추가, 수정 또는 삭제해야 하는 개체를 찾는 방법(코드 첨부)

LINQ, Lambda 식 및 대리자를 사용하여 두 컬렉션을 빠르게 비교하고 추가, 수정 또는 삭제해야 하는 개체를 찾는 방법(코드 첨부)

云罗郡主
云罗郡主앞으로
2018-10-15 14:06:193244검색

이 문서의 내용은 LINQ, Lambda 식 및 대리자를 사용하여 두 컬렉션을 빠르게 비교하고 (코드 포함) 추가, 수정 및 삭제해야 하는 개체를 찾는 방법에 대한 것입니다. 도움이 필요한 친구들이 참고하면 도움이 되리라 믿습니다.

직장에서 우리는 다음과 같이 두 컬렉션을 비교해야 하는 시나리오에 자주 직면합니다.

  1. 페이지 컬렉션 데이터 수정 사항을 데이터베이스에 저장해야 함

  2. 업스트림 데이터를 이 시스템 데이터베이스에 완전히 동기화

이러한 시나리오에서는 추가, 업데이트, 삭제해야 할 데이터를 식별해야 합니다. 각 애플리케이션마다 비교해야 하는 개체 유형이 일치하지 않기 때문에 비교적 일반적인 방법을 작성했습니다. 이 과정에서 다음 두 가지 핵심 개념을 이해해야 합니다.

  1. 고유 ID 비교: 두 객체의 고유 ID가 동일하면 두 객체는 ​​비즈니스에서 동일한 것을 나타내는 것으로 간주됩니다(보조 속성인지 여부) 현재로서는 동등하다는 점을 고려하지 않습니다.)

  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. 그러나 실제 사용에서는 두 유형이 서로 다를 수 있습니다. 결국 대상 컬렉션이 반환됩니다.

위 내용은 컬렉션 비교에 대한 내 경험입니다. 이는 데이터 용량이 작은 비즈니스 시나리오에만 부합하며 데이터 용량이 큰 경우에는 최적화되지 않았습니다. 이것이 출발점이라고 볼 수 있습니다. 더 좋은 방법이 있다면 조언을 해주셨으면 좋겠습니다.

위 내용은 LINQ, Lambda 식 및 대리자를 사용하여 두 컬렉션을 빠르게 비교하고 추가, 수정 또는 삭제해야 하는 개체를 찾는 방법(코드 첨부)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 cnblogs.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제