2008-10-02 90 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