2008-10-02 3 views
10

Представьте себе следующий тип:Лучший алгоритм для синхронизации двух IList в C# 2.0

public struct Account 
{ 
    public int Id; 
    public double Amount; 
} 

Каков наилучший алгоритм для синхронизации двух IList<Account> в C# 2.0? (Нет linq)?

Первый список (L1) является список ссылок, то вторая (L2) является один для синхронизации в соответствии с первым:

  • Все счета в L2, которые больше не присутствуют в L1 должны быть удалены из L2
  • всех счета в L2, которые все еще существуют в L1 должны быть обновлены (атрибут суммы)
  • всех счетов, которые находятся в L1, но еще не в L2 должны быть добавлены в L2

Идентификатор идентифицирует согл ounts. Нетрудно найти наивный и рабочий алгоритм, но я хотел бы знать, есть ли интеллектуальное решение для обработки этого сценария, не нарушая удобочитаемости и совершенства.

EDIT:

  • Тип счета не имеет значения, это может быть классом, имеет свойства, элементы равенства и т.д.
  • L1 и L2 не отсортированные
  • элементы L2 может не должны быть заменены элементами L1, они должны быть обновлены (поле по полю, свойство по свойству)
+0

Есть хорошая причина, вы не можете просто скопировать список ссылок? L2 = L1; звучит так, как вам нужно, исходя из критериев, которые вы указали. – 2008-10-02 14:33:11

+0

Да, список L2 - это BindingList, используемый в качестве источника данных для сетки. Объекты L1 и L2 не одного типа. L2 содержит объекты презентации, которые должны быть обновлены в отношении характеристик и мигания сетки. – 2008-10-03 19:17:50

ответ

5

Для начала я бы избавился от изменяемой структуры. Типы взаимозаменяемых значений - это в корне плохая вещь. (Как и публичные поля, ИМО.)

Возможно, стоит построить словарь, чтобы вы могли легко сравнить содержимое этих двух списков. Как только у вас будет такой простой способ проверить наличие/отсутствие, остальное должно быть простым.

Если честно, это звучит так, будто вы в основном хотите, чтобы L2 была полной копией L1 ... очистите L2 и просто вызовите AddRange? Или в том, что вы также хотите выполнять другие действия, пока вы меняете L2?

+0

Я соглашаюсь на изменчивые структуры и публичные поля. Но тип учетной записи здесь не очень важен: это может быть класс, есть члены инкапсуляции и равенства и т. Д. Я сосредоточен на синхронизации двух списков, заботясь о том, чтобы не заменять экземпляры элементов L2 элементами L1. Элементы L2 должны быть обновлены. – 2008-10-02 09:43:44

0

В дополнение к комментарию Джона Скита сделайте свою учетную запись struct классом и переопределите метод Equals() и GetHashCode(), чтобы получить хорошую проверку равенства.

0

L2 = L1.clone()?

... но, я думаю, вы забыли что-то упомянуть.

2

Если ваши два списка отсортированы, вы можете просто пройти через них в тандеме. Это операция O (m + n). Следующий код может помочь:

class Program 
{ 
    static void Main() 
    { 
     List<string> left = new List<string> { "Alice", "Charles", "Derek" }; 
     List<string> right = new List<string> { "Bob", "Charles", "Ernie" }; 

     EnumerableExtensions.CompareSortedCollections(left, right, StringComparer.CurrentCultureIgnoreCase, 
      s => Console.WriteLine("Left: " + s), s => Console.WriteLine("Right: " + s), (x,y) => Console.WriteLine("Both: " + x + y)); 
    } 
} 

static class EnumerableExtensions 
{ 
    public static void CompareSortedCollections<T>(IEnumerable<T> source, IEnumerable<T> destination, IComparer<T> comparer, Action<T> onLeftOnly, Action<T> onRightOnly, Action<T, T> onBoth) 
    { 
     EnumerableIterator<T> sourceIterator = new EnumerableIterator<T>(source); 
     EnumerableIterator<T> destinationIterator = new EnumerableIterator<T>(destination); 

     while (sourceIterator.HasCurrent && destinationIterator.HasCurrent) 
     { 
      // While LHS < RHS, the items in LHS aren't in RHS 
      while (sourceIterator.HasCurrent && (comparer.Compare(sourceIterator.Current, destinationIterator.Current) < 0)) 
      { 
       onLeftOnly(sourceIterator.Current); 
       sourceIterator.MoveNext(); 
      } 

      // While RHS < LHS, the items in RHS aren't in LHS 
      while (sourceIterator.HasCurrent && destinationIterator.HasCurrent && (comparer.Compare(sourceIterator.Current, destinationIterator.Current) > 0)) 
      { 
       onRightOnly(destinationIterator.Current); 
       destinationIterator.MoveNext(); 
      } 

      // While LHS==RHS, the items are in both 
      while (sourceIterator.HasCurrent && destinationIterator.HasCurrent && (comparer.Compare(sourceIterator.Current, destinationIterator.Current) == 0)) 
      { 
       onBoth(sourceIterator.Current, destinationIterator.Current); 
       sourceIterator.MoveNext(); 
       destinationIterator.MoveNext(); 
      } 
     } 

     // Mop up. 
     while (sourceIterator.HasCurrent) 
     { 
      onLeftOnly(sourceIterator.Current); 
      sourceIterator.MoveNext(); 
     } 

     while (destinationIterator.HasCurrent) 
     { 
      onRightOnly(destinationIterator.Current); 
      destinationIterator.MoveNext(); 
     } 
    } 
} 

internal class EnumerableIterator<T> 
{ 
    private readonly IEnumerator<T> _enumerator; 

    public EnumerableIterator(IEnumerable<T> enumerable) 
    { 
     _enumerator = enumerable.GetEnumerator(); 
     MoveNext(); 
    } 

    public bool HasCurrent { get; private set; } 

    public T Current 
    { 
     get { return _enumerator.Current; } 
    } 

    public void MoveNext() 
    { 
     HasCurrent = _enumerator.MoveNext(); 
    } 
} 

Вы должны быть осторожными об изменении коллекции в то время как итерация над ними, хотя.

Если они не отсортированы, то сравнение каждого элемента в одном с каждым элементом в другом - это O (mn), который становится очень болезненным.

Если вы можете скопировать значения ключей из каждой коллекции в словарь или аналогичный (т.коллекцию с приемлемой производительностью, когда ее спросили «есть ли X?»), тогда вы можете придумать что-то разумное.

0

Я знаю, что это старый пост, но вы должны проверить AutoMapper. Он будет делать именно то, что вы хотите, очень гибким и настраиваемым способом.

AutoMapper

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