Melhor algoritmo para sincronizar dois IList em C # 2.0

Imagine o seguinte tipo:

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

Qual é o melhor algoritmo para sincronizar dois IList no C # 2.0? (Sem linq)?

A primeira lista (L1) é a lista de referência, a segunda (L2) é a que se sincroniza de acordo com a primeira:

  • Todas as contas em L2 que não estão mais presentes em L1 devem ser excluídas de L2
  • Todas as contas em L2 que ainda existem em L1 devem ser atualizadas (atributo de valor)
  • Todas as contas que estão em L1, mas ainda não estão em L2, devem ser adicionadas a L2

O ID identifica contas. Não é difícil encontrar um algoritmo ingênuo e funcional, mas gostaria de saber se existe uma solução inteligente para lidar com esse cenário sem prejudicar a legibilidade e os resultados.

EDITAR :

  • Tipo de conta não importa, pode ser uma class, tem propriedades, membros de igualdade, etc.
  • L1 e L2 não estão ordenados
  • Itens L2 não podem ser substituídos por itens L1, eles devem ser atualizados (campo a campo, propriedade por propriedade)

Para começar, eu me livraria da estrutura mutável. Tipos de valores mutáveis ​​são fundamentalmente ruins. (Como são campos públicos, IMO.)

Provavelmente vale a pena criar um Dicionário para que você possa comparar facilmente o conteúdo das duas listas. Uma vez que você tenha uma maneira fácil de verificar a presença / ausência, o resto deve ser direto.

Para ser honesto, parece que você basicamente quer que o L2 seja uma cópia completa do L1 … limpe o L2 e simplesmente chame o AddRange? Ou é o ponto que você também quer tomar outras ações enquanto você está mudando L2?

Se as suas duas listas estiverem ordenadas, você pode simplesmente percorrê-las em conjunto. Esta é uma operação O (m + n). O código a seguir pode ajudar:

 class Program { static void Main() { List left = new List { "Alice", "Charles", "Derek" }; List right = new List { "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(IEnumerable source, IEnumerable destination, IComparer comparer, Action onLeftOnly, Action onRightOnly, Action onBoth) { EnumerableIterator sourceIterator = new EnumerableIterator(source); EnumerableIterator destinationIterator = new EnumerableIterator(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 { private readonly IEnumerator _enumerator; public EnumerableIterator(IEnumerable enumerable) { _enumerator = enumerable.GetEnumerator(); MoveNext(); } public bool HasCurrent { get; private set; } public T Current { get { return _enumerator.Current; } } public void MoveNext() { HasCurrent = _enumerator.MoveNext(); } } 

Você terá que ter cuidado ao modificar as collections enquanto iterar sobre elas, no entanto.

Se eles não estão classificados, então comparar cada elemento em um com todos os elementos no outro é O (mn), que fica dolorido muito rapidamente.

Se você pode suportar copiar os valores-chave de cada coleção em um Dicionário ou similar (ou seja, uma coleção com desempenho aceitável quando perguntado “está presente X?”), Então você poderia chegar a algo razoável.

Além do comentário de Jon Skeet, faça da sua conta struct uma class e substitua o método Equals () e GetHashCode () para obter uma boa verificação de igualdade.

L2 = L1.clone ()?

… mas eu acho que você esqueceu de mencionar algo.

Eu sei que este é um post antigo, mas você deve verificar o AutoMapper. Ele fará exatamente o que você quer de uma maneira muito flexível e configurável.

AutoMapper