简体   繁体   English

比较两个复杂对象列表

[英]Compare two list of complex object

I am in the situation of comparing two lists of complex objects, to find the elements inserted, the elements modified and those deleted:我处于比较两个复杂对象列表的情况,以查找插入的元素、修改的元素和删除的元素:

small example小例子

  public class pippo
{
    public int fluido;
    public int abc;
}

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
        List<pippo> lstact= new List<pippo>();
        List<pippo> lstprec = new List<pippo>();

        lstact.Add(new pippo { abc = 1, fluido = 1 });
        lstact.Add(new pippo { abc = 2, fluido = 1 });
        lstact.Add(new pippo { abc = 3, fluido = 1 });

        lstprec.Add(new pippo { abc = 1, fluido = 1 });
        lstprec.Add(new pippo { abc = 2, fluido = 1 });

        // compare two list for find item insert, deleted, modified


    }
}

To solve this correctly, you should first make the objects comparable, and then solve your problem with built-in list functions and / or LINQ.要正确解决这个问题,您应该首先使对象具有可比性,然后使用内置列表函数和/或 LINQ 解决您的问题。

First things first: Basics of object comparison第一件事:对象比较的基础知识

In C#, every class derrives from the class "object".在 C# 中,每个类都从类“对象”派生。 "object" provides every class a basic way of comparison, by saying: When im the same instance, (same place in memory), then im equal. “对象”为每个类提供了一种基本的比较方式,它说:当 im 是同一个实例时,(内存中的相同位置),那么 im 相等。

So: Normally, when you compare two objects, and nothing else is defined, C# does not compare the object's content (deep comparison), but it really checks if it is the same object instance (reference comparison).所以:通常情况下,当你比较两个对象并且没有定义其他任何东西时,C# 不会比较对象的内容(深度比较),但它会真正检查它是否是同一个对象实例(引用比较)。

So when I do this:所以当我这样做时:

var x = new pippo { abc = 1, fluido = 1};
var y = new pippo { abc = 1, fluido = 1};

and I compare the two objects, they will not be the same, because they are two different instances (the new keyword makes a new instance allright).我比较这两个对象,它们不会相同,因为它们是两个不同的实例(new 关键字可以创建一个新实例)。

Deep comparison深度对比

However, when you do the same with the String class:但是,当您对 String 类执行相同操作时:

var x = new String("hello world");
var y = new String("hello world");

And you compare these two (x == y), then it will be the same.而你比较这两个 (x == y),那么结果是一样的。 How did they do that?他们是怎么做到的?

They redefined the way strings compare themselves, by overriding the default behaviour of "object" and providing a new way of comparing those objects to others.他们通过覆盖“对象”的默认行为并提供将这些对象与其他对象进行比较的新方法,重新定义了字符串比较自身的方式。

Take a look HERE for a good example..看看这里的一个很好的例子..

In your case The correct way to implement a deep comparison is to override the "Equals" method.在您的情况下实现深度比较的正确方法是覆盖“Equals”方法。 When you do that, it is also a good practice to override the "GetHashcode" method as well.当你这样做时,覆盖“GetHashcode”方法也是一个好习惯。 They practically come as couple.他们实际上是一对。 In fact, the compiler will even warn you if you just override one of these methods instead of both.事实上,如果您只是覆盖这些方法之一而不是两者,编译器甚至会警告您。 Doing that for pippo would look like this:为 pippo 执行此操作将如下所示:

public class pippo
{
  public int fluido;
  public int abc;

  public override bool Equals(object obj) 
  {
    // If this and obj do not refer to the same type, then they are not equal.
    if (obj.GetType() != this.GetType()) return false;

    // Return true if abc and fluido fields match.
    var other = (pippo) obj;
    return (this.abc == other.abc) && (this.fluido == other.fluido);
  }

  public override int GetHashCode() 
  {
    //something like this. 
    return ($"{this.abc}/{this.fluido}").GetHashCode();
  }
}

OK, now C# knows how to check if pippos are "equal".好的,现在 C# 知道如何检查 pippos 是否“相等”。 Now, we can start using built-in list operations of C# / or LINQ to fulfill what you wanted.现在,我们可以开始使用 C# / 或 LINQ 的内置列表操作来实现您想要的。

For example, to compare the lists and get inserted and deleted elements, you would do that例如,要比较列表并插入和删除元素,您可以这样做

(there might be syntax errors here, but it should show the trick: (这里可能有语法错误,但它应该显示出窍门:

var newElements = lstact.Where(p=>!lstprec.Contains(p)).ToList();
var deletedElements = lstprec.Where(p=>!lstact.Contains(p)).ToList();

or by doing things like that:或者通过做这样的事情:

 foreach(var p in lstprec)
 if(!lstact.Contains(p))
    ....

As you can see, can do plenty of cool things if you invest a bit into the pippo class, and you can do them right ...正如你所看到的,如果你在 pippo 类上投入一点,你可以做很多很酷的事情,而且你可以把它们做......

Here is linq solution :这是 linq 解决方案:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConsoleApplication2
{
    class Program
    {
        static void Main(string[] args)
        {
            List<pippo> lstact = new List<pippo>();
            List<pippo> lstprec = new List<pippo>();

            lstact.Add(new pippo { abc = 1, fluido = 1 });
            lstact.Add(new pippo { abc = 2, fluido = 1 });
            lstact.Add(new pippo { abc = 3, fluido = 1 });

            lstprec.Add(new pippo { abc = 1, fluido = 1 });
            lstprec.Add(new pippo { abc = 2, fluido = 1 });

            var matches = (from act in lstact
                           join prec in lstprec on act equals prec into pr
                           from prec in pr.DefaultIfEmpty()
                           select new { act = act, prec = prec }
                          ).ToList();

            foreach (var match in matches)
            {
                if(match.act == null)
                {
                    Console.WriteLine("B does not match A, abc = '{0}', prec = '{1}'", match.prec.abc, match.prec.fluido);
                }
                else
                {
                    if(match.prec == null)
                    {
                        Console.WriteLine("A does not match B, abc = '{0}', prec = '{1}'", match.act.abc, match.act.fluido);
                    }
                    else
                    {
                        Console.WriteLine("A matches B, abc = '{0}', prec = '{1}'", match.act.abc, match.act.fluido);
                    }
                }
            }
            Console.ReadLine();
        }
    }
    public class pippo : IEquatable<pippo>
    {
        public int abc { get;set;}
        public int fluido { get;set;}

        public Boolean Equals(pippo other)
        {
            return (this.abc == other.abc) && (this.fluido == other.fluido);
        }
        public override int  GetHashCode()
        {
            return (this.abc.ToString() + "^" + this.fluido.ToString()).GetHashCode();
        }

    }

}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM