我有以下数组:
var original= new int[] { 2, 1, 3 };
var target = new int[] { 1, 3, 4 };
enum Operation {Added,Removed}
我想执行一个返回以下内容的LINQ查询:
{{2,Removed},{4,Added}}
限制:我希望LINQ能够非常有效地执行此操作并避免使用O(n ^ 2)样式算法。
答案 0 :(得分:3)
在这种情况下,LINQ解决方案可能不是最佳选择。
这将生成一个包含所需结果的字典。
Dictionary<int, Operation> difference = new Dictionary<int,Operation>();
foreach (int value in original) {
difference.Add(value, Operation.Removed);
}
foreach (int value in target) {
if (difference.ContainsKey(value)) {
difference.Remove(value);
} else {
difference.Add(value, Operation.Added);
}
}
为了保持字典的大小,也许可以将字符串循环。我来看看......
编辑:
这是:
Dictionary<int, Operation> difference = new Dictionary<int,Operation>();
IEnumerator<int> o = ((IEnumerable<int>)original).GetEnumerator();
IEnumerator<int> t = ((IEnumerable<int>)target).GetEnumerator();
bool oActive=true, tActive=true;
while (oActive || tActive) {
if (oActive && (oActive = o.MoveNext())) {
if (difference.ContainsKey(o.Current)) {
difference.Remove(o.Current);
} else {
difference.Add(o.Current, Operation.Removed);
}
}
if (tActive && (tActive = t.MoveNext())) {
if (difference.ContainsKey(t.Current)) {
difference.Remove(t.Current);
} else {
difference.Add(t.Current, Operation.Added);
}
}
}
EDIT2:
我做了一些性能测试。第一个版本的运行速度提高了10%-20%,包括排序列表和随机排序列表。
我列出了1到100000的数字,随机跳过了10%的数字。在我的机器上,代码的第一个版本在大约16毫秒内匹配列表。
答案 1 :(得分:1)
enum Operation { Added, Removed, }
static void Main(string[] args)
{
var original = new int[] { 2, 1, 3 };
var target = new int[] { 1, 3, 4 };
var result = original.Except(target)
.Select(i => new { Value = i, Operation = Operation.Removed, })
.Concat(
target.Except(original)
.Select(i => new { Value = i, Operation = Operation.Added, })
);
foreach (var item in result)
Console.WriteLine("{0}, {1}", item.Value, item.Operation);
}
我不认为你可以使用LINQ扩展方法只使用一次通过LINQ,但可能能够编写自定义扩展方法。您的权衡可能是延期执行的损失。比较两者的相对表现会很有意思。
答案 2 :(得分:0)
你运气不好。如果您在评论中说明列表未排序,则无法计算您在单个前向传递中寻找的差异。考虑:
{ 1, 2, 3, 4, 5, 6, 7, ...
{ 1, 2, 3, 6, 7, 8, 9, ...
在遇到的第一个差异(4对6)时,您无法确定是否正在查看4&amp;的删除。 5(如果两个列表单调增加,或者插入分别为6,7,8和9),如果列表继续这样的情况就会出现这种情况:
{ 1, 2, 3, 4, 5, 6, 7, 8, 9,...
{ 1, 2, 3, 6, 7, 8, 9, 4, 5, 6, 7, 8, 9,...
答案 3 :(得分:0)
这将在单次传递中实现结果,但是我不确定GroupBy操作的复杂性。
var original= new int[] { 1, 2, 3 };
var target = new int[] { 1, 3, 4 };
var output = original.Select( i => new { I = i, L = "o" } )
.Concat( target.Select( i => new { I = i, L = "t" } ) )
.GroupBy( i => i.I ).Where( i => i.Count() == 1 )
.Select( i => new { I = i.Key, S = (i.ElementAt( 0 ).L == "o" ? Operation.Removed : Operation.Added) } );