質問者が Java ソリューションを探していたことは知っていますが、C# で実装するアルゴリズムを探しているときにこの質問に出くわしました。
これは、単純な IListDifference 値の列挙を生成する私のソリューションです: ItemAddedDifference、ItemRemovedDifference、または ItemMovedDifference のいずれかです。
ソース リストの作業コピーを使用して、アイテムごとに、ターゲット リストと一致するように変換するために必要な変更を確立します。
public class ListComparer<T>
{
public IEnumerable<IListDifference> Compare(IEnumerable<T> source, IEnumerable<T> target)
{
var copy = new List<T>(source);
for (var i = 0; i < target.Count(); i++)
{
var currentItemsMatch = false;
while (!currentItemsMatch)
{
if (i < copy.Count && copy[i].Equals(target.ElementAt(i)))
{
currentItemsMatch = true;
}
else if (i == copy.Count())
{
// the target item's index is at the end of the source list
copy.Add(target.ElementAt(i));
yield return new ItemAddedDifference { Index = i };
}
else if (!target.Skip(i).Contains(copy[i]))
{
// the source item cannot be found in the remainder of the target, therefore
// the item in the source has been removed
copy.RemoveAt(i);
yield return new ItemRemovedDifference { Index = i };
}
else if (!copy.Skip(i).Contains(target.ElementAt(i)))
{
// the target item cannot be found in the remainder of the source, therefore
// the item in the source has been displaced by a new item
copy.Insert(i, target.ElementAt(i));
yield return new ItemAddedDifference { Index = i };
}
else
{
// the item in the source has been displaced by an existing item
var sourceIndex = i + copy.Skip(i).IndexOf(target.ElementAt(i));
copy.Insert(i, copy.ElementAt(sourceIndex));
copy.RemoveAt(sourceIndex + 1);
yield return new ItemMovedDifference { FromIndex = sourceIndex, ToIndex = i };
}
}
}
// Remove anything remaining in the source list
for (var i = target.Count(); i < copy.Count; i++)
{
copy.RemoveAt(i);
yield return new ItemRemovedDifference { Index = i };
}
}
}
これが IEnumerable でカスタム拡張メソッドを使用していることに気付きました - 'IndexOf':
public static class EnumerableExtensions
{
public static int IndexOf<T>(this IEnumerable<T> list, T item)
{
for (var i = 0; i < list.Count(); i++)
{
if (list.ElementAt(i).Equals(item))
{
return i;
}
}
return -1;
}
}