tips c# .net algorithm optimization list

c# tips



El mejor algoritmo para sincronizar dos IList en C#2.0 (5)

Además del comentario de Jon Skeet, haz que tu cuenta genere una clase y anule el método Equals () y GetHashCode () para obtener una buena comprobación de igualdad.

Imagina el siguiente tipo:

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

¿Cuál es el mejor algoritmo para sincronizar dos IList<Account> en C # 2.0? (No linq)?

La primera lista (L1) es la lista de referencia, la segunda (L2) es la que se sincroniza de acuerdo con la primera:

  • Todas las cuentas en L2 que ya no están presentes en L1 deben borrarse de L2
  • Todas las cuentas en L2 que todavía existen en L1 deben actualizarse (atributo de cantidad)
  • Todas las cuentas que están en L1 pero aún no están en L2 deben agregarse a L2

Id identifica cuentas No es demasiado difícil encontrar un algoritmo ingenuo y de trabajo, pero me gustaría saber si hay una solución inteligente para manejar este escenario sin arruinar la legibilidad y las perforaciones.

EDITAR :

  • El tipo de cuenta no importa, podría ser una clase, tiene propiedades, miembros de igualdad, etc.
  • L1 y L2 no están clasificados
  • Los elementos L2 no pueden ser reemplazados por elementos L1, deben actualizarse (campo por campo, propiedad por propiedad)

L2 = L1.clone ()?

... pero supongo que olvidó mencionar algo.


Para empezar, me desharía de la estructura mutable. Los tipos de valores mutables son fundamentalmente malos. (Como son los campos públicos, IMO.)

Probablemente valga la pena construir un diccionario para que pueda comparar fácilmente el contenido de las dos listas. Una vez que tenga esa manera fácil de verificar presencia / ausencia, el resto debería ser sencillo.

Sin embargo, para ser sincero, parece que básicamente quieres que L2 sea una copia completa de L1 ... ¿borras L2 y simplemente llamas a AddRange? ¿O es el punto de que también quieres tomar otras medidas mientras estás cambiando L2?


Sé que esta es una publicación anterior pero deberías echarle un vistazo a AutoMapper. Hará exactamente lo que quiera de una manera muy flexible y configurable.

AutoMapper


Si sus dos listas están ordenadas, entonces simplemente puede caminar a través de ellas en tándem. Esta es una operación O (m + n). El siguiente código podría ayudar:

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(); } }

Sin embargo, tendrá que tener cuidado con la modificación de las colecciones mientras itera sobre ellas.

Si no están clasificados, entonces la comparación de cada elemento en uno con cada elemento en el otro es O (mn), que se pone muy rápido.

Si puede soportar copiar los valores clave de cada colección en un diccionario o similar (es decir, una colección con un rendimiento aceptable cuando se le pregunta "¿está presente X?"), Entonces podría llegar a algo razonable.