ホームページ >バックエンド開発 >C#.Net チュートリアル >LINQ、ラムダ式、デリゲートを使用して 2 つのコレクションをすばやく比較し、追加、変更、または削除する必要があるオブジェクトを見つける方法 (コード添付)

LINQ、ラムダ式、デリゲートを使用して 2 つのコレクションをすばやく比較し、追加、変更、または削除する必要があるオブジェクトを見つける方法 (コード添付)

云罗郡主
云罗郡主転載
2018-10-15 14:06:193294ブラウズ

この記事の内容は、LINQ、ラムダ式、デリゲートを使用して 2 つのコレクションをすばやく比較し、(コードを使用して) 追加、変更、削除する必要があるオブジェクトを見つける方法についてです。 、困っている友達が参考になれば幸いです。

職場では、次のような 2 つのコレクションを比較する必要があるシナリオによく遭遇します。

  1. ページ コレクション データの変更をデータベースに保存する必要がある

  2. アップストリーム データをシステム データベースに完全に同期する

これらのシナリオでは、追加、更新、削除する必要があるデータを特定する必要があります。 , アプリケーションごとに、比較する必要があるオブジェクトの種類がバラバラなので、比較的一般的な方法を書きました。このプロセスでは、理解する必要がある 2 つの中心的な概念があります。

  1. 一意の識別の比較: 2 つのオブジェクトの一意の識別が等しい場合、2 つのオブジェクトはオブジェクトはビジネス用語では同じものを表します (二次属性が等しいかどうかはまだ考慮されていません)。

  2. エンティティ比較: ビジネスにおいて 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、ラムダ式、デリゲートを使用して 2 つのコレクションをすばやく比較し、追加、変更、または削除する必要があるオブジェクトを見つける方法 (コード添付)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はcnblogs.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。