Сравните два списка сложного объекта - PullRequest
0 голосов
/ 20 марта 2020

Я нахожусь в ситуации сравнения двух списков сложных объектов, чтобы найти вставленные элементы, измененные и удаленные элементы:

маленький пример

  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


    }
}

Ответы [ 2 ]

0 голосов
/ 20 марта 2020

Вот решение 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();
        }

    }

}
0 голосов
/ 20 марта 2020

Чтобы решить это правильно, вы должны сначала сделать объекты сопоставимыми, а затем решить вашу проблему с помощью встроенных функций списка и / или LINQ.

Перво-наперво: основы сравнения объектов

В C# каждый класс является производным от класса «объект». «объект» предоставляет каждому классу базовый c способ сравнения, говоря: если я один и тот же экземпляр (то же место в памяти), то я равняюсь.

Итак: обычно, когда вы сравниваете два объекта и ничего больше не определено, C# не сравнивает содержимое объекта (глубокое сравнение), но действительно проверяет, является ли он тем же экземпляром объекта (ссылочное сравнение).

Поэтому, когда я делаю это:

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

и я сравниваю два объекта, они не будут одинаковыми, потому что это два разных экземпляра (новое ключевое слово делает новый экземпляр в порядке).

Глубокое сравнение

Однако, когда вы делаете то же самое с классом String:

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

И вы сравниваете эти два (x == y), тогда это будет то же самое. Как они это сделали?

Они переопределили способ сравнения строк, переопределив поведение «объекта» по умолчанию и предоставив новый способ сравнения этих объектов с другими.

Посмотрите ЗДЕСЬ для хорошего примера ..

В вашем случае Правильный способ осуществления глубокого сравнения - переопределить метод "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, и вы можете делать их right ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...