简体   繁体   中英

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.

First things first: Basics of object comparison

In C#, every class derrives from the class "object". "object" provides every class a basic way of comparison, by saying: When im the same instance, (same place in memory), then im equal.

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).

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).

Deep comparison

However, when you do the same with the String class:

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. 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. When you do that, it is also a good practice to override the "GetHashcode" method as well. 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:

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". Now, we can start using built-in list operations of C# / or LINQ to fulfill what you wanted.

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 ...

Here is linq solution :

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();
        }

    }

}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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