【问题标题】:Compare two list of complex object比较两个复杂对象列表
【发布时间】:2020-03-20 16:32:22
【问题描述】:

我在比较两个复杂对象列表的情况下,找到插入的元素,修改的元素和删除的元素:

小例子

  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


    }
}

【问题讨论】:

  • 我想我不明白,你会怎么做?我想了多个循环来解决问题
  • 左外连接给出三种类型的结果 1) A and B = null (no match) 2) A = null (no match) and B 3) A = B (match)
  • 您能否发布一个代码示例,说明您将如何使用上面的两个列表来查找修改、插入和删除的元素?

标签: c# .net list object compare


【解决方案1】:

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

    }

}

【讨论】:

    【解决方案2】:

    要正确解决这个问题,您应该首先使对象具有可比性,然后使用内置列表函数和/或 LINQ 解决您的问题。

    首要任务:对象比较的基础知识

    在 C# 中,每个类都派生自“对象”类。 “对象”为每个类提供了一种基本的比较方式,即:当我是同一个实例时,(在内存中的同一个地方),那么我就相等。

    所以: 通常,当您比较两个对象时,没有定义其他内容,C# 不会比较对象的内容(深度比较),但它确实会检查它是否是同一个对象实例(引用比较)。

    所以当我这样做时:

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

    我比较两个对象,它们不会相同,因为它们是两个不同的实例(new 关键字可以创建一个新实例)。

    深度比较

    但是,当您对 String 类执行相同操作时:

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

    你比较这两个(x == y),那么它会是一样的。他们是怎么做到的?

    他们通过覆盖“对象”的默认行为并提供一种将这些对象与其他对象进行比较的新方法,重新定义了字符串比较自身的方式。

    看看HERE 一个很好的例子..

    你的情况 实现深度比较的正确方法是重写“Equals”方法。 当你这样做时,重写“GetHashcode”方法也是一个好习惯。他们实际上是一对夫妇。事实上,如果您只覆盖其中一种方法而不是同时覆盖这两种方法,编译器甚至会警告您。为 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();
      }
    }
    

    好的,现在 C# 知道如何检查 pippos 是否“相等”。现在,我们可以开始使用 C# / 或 LINQ 的内置列表操作来满足您的需求。

    例如,要比较列表并获取插入和删除的元素,您可以这样做

    (这里可能有语法错误,但它应该显示技巧:

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

    或通过这样做:

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

    如您所见,如果您在 pippo 课程上投入一点,可以做很多很酷的事情,而且您可以正确...

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2017-05-17
      • 1970-01-01
      • 1970-01-01
      • 2012-05-14
      • 2011-04-01
      • 1970-01-01
      相关资源
      最近更新 更多