2013-12-02 4 views
6

В моем текущем проекте я пытаюсь сравнить два списка объектов, выясняя, были ли добавлены, удалены, изменены или остались объекты.Поиск разницы между двумя списками

Я используя IEnumerable.Except для этого следующим образом:

Dim newOnes = current.Except(previous, equalityComparer).ToList 
Dim removedOnes = previous.Except(current, equalityComparer).ToList() 
Dim existingOnes = current.Except(newOnes, equalityComparer).ToList 
Dim changedOnes = existingOnes.Except(previous, changedComparer).ToList() 
Dim unchangedOnes = existingOnes.Except(changedOnes, equalityComparer).ToList() 

Для этого я должен реализовать IEqualityComparers.
Если вы обнаружили, что пара объектов изменилась в значениях свойств (changedOnes), мне нужно написать «changedComparer», который является IEqualityComparer, который проверяет не-идентификационные поля (такие как коллекции участников).

Как метод Except, по-видимому, сначала проверяет GetHashCode и не переходит к методу Equals, если хеши равны, моя установка разваливается.

Я в настоящее время решения это следующим образом:

Public Overloads Function GetHashCode(obj As Family) As Integer Implements IEqualityComparer(Of Family).GetHashCode 
    Dim hashCode As Long = 17 
    If obj.ClientCode IsNot Nothing Then hashCode = CInt(((hashCode * 397) Xor obj.ClientCode.GetHashCode()) Mod Integer.MaxValue) 
    ' SNIP a bunch more property fields 
    If obj.Members IsNot Nothing Then hashCode = CInt(((hashCode * 397) Xor obj.Members.GetHashCode()) Mod Integer.MaxValue) 

    Return CInt(hashCode Mod Integer.MaxValue) 
End Function 

Добавление хэша списка членов, всегда возвращает другой хэш, как он проверяет экземпляр, а не содержание. Это работает пока, но с курса удаляет все преимущества наличия хэша.

UPDATE
Что я ищу это не лучше Equals метод, но я подвергаю сомнению всю свою методологию (может быть, есть что-то OOTB, я должен использовать другой интерфейс). В противном случае, как я могу получить хороший GetHashcode, когда необходимо учесть мою коллекцию имущества?

ответ

1

Я думаю, что Enumerable.SequenceEqual должен делать трюк, так как он всегда использует сопоставитель равенства по умолчанию, не требуя реализации IEqualityComparer. Однако предостережение заключается в том, что он также проверяет сравнение заказов.

+0

Я уже использую SequenceEqual в моей функции Equals. Проблема заключается в функции GetHashCode(). –

1

Я использую класс KeyEqualityComparer<T, TKey>, который позволяет мне указать ключ, извлекающий лямбду, для обнаружения любых новых или удаленных элементов.

Я внедрил утилиту ListDifference (в C#, извините), которая при предоставлении keyExtractor и comparer выплескивает список новых, удаленных, измененных и неизменных элементов. Это делает очевидную вещь, то есть

public ListDifference(IEnumerable<T> original, 
         IEnumerable<T> updated, 
         Func<T, object> keyExtractor = null, 
         Func<T, T, bool> comparer = null) 
{ 
    if (keyExtractor == null) 
    keyExtractor = t => t; 

    AddedItems = updated.Difference(original, keyExtractor); 
    RemovedItems = original.Difference(updated, keyExtractor); 

    var matches = from u in updated 
       from o in original 
       where keyExtractor(u).Equals(keyExtractor(o)) 
       select Tuple.Create(o, u); 

    if (comparer == null) 
    { 
    //we are unable to detect changed items 
    ChangedItems = null; 
    UnchangedItems = matches; 
    } 
    else 
    { 
    ChangedItems = matches.Where(t => !comparer(t.Item1, t.Item2)); 
    UnchangedItems = matches.Where(t => comparer(t.Item1, t.Item2)); 
    } 
} 
+0

Это выглядит совершенно так же, как и с моим классом Comparer с той разницей, что вы используете Funcs вместо Comparers. Для тестирования я считаю, что предпочитаю сравнивать логику сравнения в классе сравнения. –

+0

Да, это в основном то же самое, оно просто инкапсулировано в модуль, который я знаю, работает, и он закорочен и удобнее звонить. – SWeko

Смежные вопросы