2008-10-02 96 views
10

設想以下類型:最佳算法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

全部帳戶的ID識別ACC ounts。找到一個天真的工作算法並不難,但我想知道是否有一個智能的解決方案來處理這種情況,而不會破壞可讀性和性能。

編輯

  • 帳戶類型沒有關係,是可能是一流的,具有性,平等成員等
  • 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

我同意可變結構和公共領域。但是Account類型在這裏並不重要 - 它可能是一個類,有封裝和相等成員等。我關注於同步兩個列表,注意不要用L1項目替換L2項目的實例。 L2項目必須更新。 – 2008-10-02 09:43:44

0

除了Jon Skeet的評論,您的帳戶結構類和重寫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