比较两个IEnumerable以检测更改

时间:2012-03-23 10:09:54

标签: c# .net algorithm comparison ienumerable

对于我在这里的第一篇文章,我有一个关于IEnumerable比较的问题。 我有一个基于枚举逻辑的可绑定结构。 IEnumerable的内容随着时间的推移而变化,我必须手动触发CollectionChanged事件。

我有一个非常天真的算法,它允许我检测IEnumerable的两个状态之间的简单更改(简单添加,简单删除,多次添加,多次删除)但它不是非常有效并且不会检测到所有内容。

我需要的一个简单示例:

IEnumerable的状态1: A * B * C * D * E

IEnumerable的状态2: A * C * B * D * D1

对于这个例子,我必须检测

  • 一次移动操作:B将索引从1更改为2
  • 一个添加操作:D1插入索引4
  • 一次删除操作:E已被删除

是否有算法尽可能有效地解决这个问题(O(nLog(n))会是一个好的开始)?

谢谢!

2 个答案:

答案 0 :(得分:1)

如果您更喜欢使用Linq,这里有一个基于您的示例的简单解决方案..抱歉但不确定性能..

var a = new List<string>{"A","B","C","D","E"};
var b = new List<string>{"A","C","B","D","D1"};

var removed = a.Except(b);
var moved = a.Where(x => b[a.IndexOf(x)] != x && !removed.Contains(x));
List<string> newlyInserted = new List<string>();
foreach (var item in removed)
{
    //Newly inserted into the list - D1
    newlyInserted.Add(b[a.IndexOf(item)]);
    //Index of D1 if required
    var indexOfNewlyAddedItem = a.IndexOf(item);
}

或只是

var newlyAdded = b.Except(a);

答案 1 :(得分:1)

这是未经编译的,未经测试且至少部分伪造的代码。

鉴于单个移动检测已足够物品只能向前移动,向后移动将是移动或移除另一个物品的结果

e.g。 IEnumerable的状态1:A * B * C * D * E

IEnumerable的状态2:A * D * B * C * D1

结果B和C都向前发展。

enum1pos = -1;
enum2pos = 0;
  Value2 = enum2.Next()
  enum2pos++;
List<int> SkipList = new SkipList();
while(enum1 has values left)
{
  Value1 = enum1.Next()
  enum1pos++;
  //Skip over moved items.
  while (SkipList.Count > 0 && SkipList[0] == enum2.Position)
  {
    Value2 = enum2.Next()
    enum2pos++;
  }
  if (Value1 == Value2)
    Value2 = enum2.Next()
    enum2pos++;
    continue;

  int temp = enum2pos;
  while(Value1 !=Value and enum2 has more values)
  {
    Value2 = enum2.Next();
    enum2pos++;
  }
  if(Value1 != Value2)
    ItemDeleted(Value1);
  else
  {
    ItemMoved(Value1, enum2pos);
    SkipList.Add(enum2pos);
  }
  //This is expensive for IEnumerable!
  enum2.First();
  loop temp times
    enum2.Next();
  //if 
}
while (enum2 has values left)
{
  while (SkipList.Count > 0 && SkipList[0] == enum2.Position)
  {
    Value2 = enum2.Next()
    enum2pos++;
  }
  if (enum2 has values left)
  Added(Value2, enum2pos)
}

结果: 比较A和A
接下来
比较B和D
找到B
B已移动 - &gt; 2
将2添加到跳过列表
重置枚举2
比较C和D
找到C
C Moved - &gt; 3
将3添加到跳过列表中 重置枚举2
接下来
比较D和D
接下来
跳过(2)
跳过(3)
比较E和D1
找到E
删除(E)
接下来
Enum结束 加入(D1,4)

我认为如果enum2pos太过落后,看看它是否已被移除,并且如果它没有为它在enum1中的原始位置添加跳过,则会有一个保存,这将有助于enum2的位置被重置所有的时间。