Best algorithm for synchronizing two IList in C# 2.0

前端 未结 6 1051
忘了有多久
忘了有多久 2020-12-10 05:12

Imagine the following type:

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

What is the best algorithm to synchroniz

6条回答
  •  -上瘾入骨i
    2020-12-10 05:29

    If your two lists are sorted, then you can simply walk through them in tandem. This is an O(m+n) operation. The following code could help:

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

    You'll have to be careful about modifying the collections while iterating over them, though.

    If they're not sorted, then comparing every element in one with every element in the other is O(mn), which gets painful really quickly.

    If you can bear to copy the key values from each collection into a Dictionary or similar (i.e. a collection with acceptable performance when asked "is X present?"), then you could come up with something reasonable.

提交回复
热议问题