Сравнивая две коллекции - PullRequest
       8

Сравнивая две коллекции

2 голосов
/ 04 августа 2010

У меня есть то, что кажется общей проблемой / паттерном. две коллекции одного и того же объекта. Объект имеет ряд свойств и несколько вложенных объектов внутри него. У автомобиля есть свойство id, которое является уникальным идентификатором.

Я хочу найти способ LINQ сделать различий, который включает в себя:

  1. Предметы в одной коллекции, а не в другой (наоборот)
  2. Для элементов, которые соответствуют, есть ли какие-либо изменения (изменения будут сравнивать все свойства?

Ответы [ 2 ]

10 голосов
/ 04 августа 2010

Вы можете использовать метод Enumerable.Except().При этом используется компаратор (либо по умолчанию, либо тот, который вы указали) для оценки того, какие объекты находятся в обеих последовательностях, или только в одном:

var sequenceA = new[] { "a", "e", "i", "o", "u" };
var sequenceB = new[] { "a", "b", "c" };

var sequenceDiff = sequenceA.Except( sequenceB );

Если вы хотите выполнить полное разделение обеих последовательностей (A-B) union (B-A), выпридется использовать:

var sequenceDiff = 
         sequenceA.Except( sequenceB ).Union( sequenceB.Except( sequenceA ) );

Если у вас сложный тип, вы можете написать IComparer<T> для вашего типа T и использовать перегрузку, которая принимает компаратор.

Для второгоЧасть вашего вопроса, вам нужно будет свернуть свою собственную реализацию, чтобы сообщить, какие свойства типа отличаются .. нет ничего встроенного в .NET BCL напрямую.Вы должны решить, какую форму примет эта отчетность?Как бы вы определили и выразили различия в сложном типе?Вы, конечно, можете использовать рефлексию для этого ... но если вы имеете дело только с одним типом, я бы этого избегал и написал бы специально для него разностную утилиту.Если вы собираетесь поддерживать диапазон типов borad, тогда рефлексия может иметь больше смысла.

2 голосов
/ 04 августа 2010

Вы уже получили отличный ответ для своей первой половины.Вторая половина, как объясняет Л.Бушкин, не может быть выполнена классами BCL напрямую.Вот простой метод, который просматривает все общедоступные устанавливаемые свойства (примечание: возможно, что в этих случаях gettor не является общедоступным!) И сравнивает их одно за другим.Если два объекта равны на 100%, он вернет true.Иначе, это произойдет рано и вернет false:

static bool AllSettablePropertiesEqual<T>(T obj1, T obj2)
{
    PropertyInfo[] info1 = obj1.GetType().GetProperties(
        BindingFlags.Public |
        BindingFlags.SetProperty |
        BindingFlags.Instance);      // get public properties

    PropertyInfo[] info2 = obj2.GetType().GetProperties(
        BindingFlags.Public |
        BindingFlags.SetProperty |
        BindingFlags.Instance);      // get public properties

    // a loop is easier than linq here, and we can break out quick:
    for (var i = 0; i < info1.Length; i++)
    {
        var value1 = info1[i].GetValue(obj1, null);
        var value2 = info2[i].GetValue(obj2, null)
        if(value1 == null || value2 ==null)
        {
            if(value1 != value2)
                return false;
        }
        else if (!value1.Equals(value2))
        {
            return false;
        }
    }
    return true;
}

Вы можете легко добавить этот метод к стандартному выражению LINQ, например:

var reallyReallyEqual = from itemA in listA
                        join itemB in listB 
                          on AllSettablePropertiesEqual(itemA, itemB)
                        select itemA;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...