LINQ 比较两个 Genreic 相同类型的列表并获取添加、删除和未更改项目的结果

LINQ Compare Two Genreic Same Type of List and Get Result of Which item added,removed and nochange

我有两个列表

  List<Employee> previous=new List<Employee>()
        {
            new Employee()
            {
                Id = 1,
                Name = "1"
            },
            new Employee()
            {
                Id = 2,
                Name = "2"
            },
            new Employee()
            {
                Id = 6,
                Name = "6"
            },
            new Employee()
            {
                Id = 8,
                Name = "8"
            }
        };

        List<Employee> latest=new List<Employee>()
        {
            new Employee()
            {
                Id = 1,
                Name = "1"
            },
            new Employee()
            {
                Id = 3,
                Name = "3"
            },
            new Employee()
            {
                Id = 5,
                Name = "5"
            },
            new Employee()
            {
                Id = 6,
                Name = "6"
            }
        };

现在我想比较并想要像下面这样的结果,它告诉我是哪个项目

  1. 已添加(如果以前不存在但最近也存在)
  2. 已删除(如果在以前存在但在最新不存在)
  3. NoChange(如果在之前和最新版本中都存在)

看起来像

    var employeeActions = new List<EmployeeStatus>()
        {
            new EmployeeStatus()
            {
                Action = "NoChange",
                Employee = new Employee()
                {
                    Id = 1,
                    Name = "1"
                }
            },
            new EmployeeStatus(){
                Action = "Removed",
                Employee =  new Employee()
                {
                    Id = 2,
                    Name = "2"
                }
            },
            new EmployeeStatus(){
                Action = "Added",
                Employee =  new Employee()
                {
                    Id = 3,
                    Name = "3"
                }
            },
            new EmployeeStatus(){
                Action = "Added",
                Employee =   new Employee()
                {
                    Id = 5,
                    Name = "5"
                }
            },
            new EmployeeStatus(){ 
                Action = "NoChange",
                Employee = new Employee()
                {
                    Id = 6,
                    Name = "6"
                }
            },
            new EmployeeStatus(){ 
                Action = "Removed",
                Employee =  new Employee()
                {
                    Id = 8,
                    Name = "8"
                }
            }
        };

如何使用 LINQ to Object 实现?

这很难单独使用 LINQ to Object,基本上运行时内置的所有类型都可以让您获得以下内容:

  • 添加了哪些(使用Except扩展方法)
  • 去掉了哪些(这里也用Except扩展的方式,只是把两个集合的顺序倒过来)
  • 哪些没有改变(做一个连接)

但是,按照您想要的顺序获取它们需要您编写代码来执行此操作,或者使用第三方库。


免责声明:我是DiffLib的作者。

我已经创建了这样一个第三方库,DiffLib,它可以完成繁重的工作。不过,您至少需要执行以下操作之一:

完成后,您可以将这两个集合扔到 Diff.Calculate 并取回生成的部分。节分为两种类型,一种包含比较相同的元素,另一种包含不同的元素。

这里有一个 LINQPad 程序来演示。您需要通过 Nuget 包添加 DiffLib。

void Main()
{
    List<Employee> previous = new List<Employee>()
    {
        new Employee() { Id = 1, Name = "1" },
        new Employee() { Id = 2, Name = "2" },
        new Employee() { Id = 6, Name = "6" },
        new Employee() { Id = 8, Name = "8" }
    };

    List<Employee> latest = new List<Employee>()
    {
        new Employee() { Id = 1, Name = "1" },
        new Employee() { Id = 3, Name = "3" },
        new Employee() { Id = 5, Name = "5" },
        new Employee() { Id = 6, Name = "6" }
    };

    var result = new List<EmployeeStatus>();
    int previousIndex = 0;
    int latestIndex = 0;
    foreach (var section in Diff.Calculate(previous, latest))
    {
        if (section.Equal)
        {
            for (int index = 0; index < section.Length1; index++)
            {
                result.Add(new EmployeeStatus { Action = "NoChange", Employee = previous[previousIndex] });
                previousIndex++;
                latestIndex++;
            }
        }
        else
        {
            for (int index = 0; index < section.Length1; index++)
            {
                result.Add(new EmployeeStatus { Action = "Removed", Employee = previous[previousIndex] });
                previousIndex++;
            }
            for (int index = 0; index < section.Length2; index++)
            {
                result.Add(new EmployeeStatus { Action = "Added", Employee = latest[latestIndex] });
                latestIndex++;
            }
        }
    }
    result.Dump();
}

public class Employee : IEquatable<Employee>
{
    public int Id { get; set; }
    public string Name { get; set; }

    public override int GetHashCode() { return Id * 23 + (Name == null ? 0 : Name.GetHashCode()); }
    public bool Equals(Employee other)
    {
        if (other == null) return false;
        if (ReferenceEquals(other, this)) return true;

        return Id == other.Id && Name == other.Name;
    }
    public override bool Equals(object other)
    {
        return Equals(other as Employee);
    }
}

public class EmployeeStatus
{
    public string Action { get; set; }
    public Employee Employee { get; set; }
}

输出: