C#比对两个大型数组 获取新增元素对应位置标记数组的实现方案
数组差异标记C#实现方案
核心逻辑采用主流对比工具通用的Myers差分算法,匹配最长公共子序列后标记插入位置,可高效处理最大70万级别的数据量,效果和Beyond Compare一致。
由于你的场景中array2仅在array1基础上插入新元素、无删除/修改原有元素的操作,算法会自动定位array1所有元素在array2中的对应位置,其余位置标记为新增即可。
完整实现代码
using System; using System.Collections.Generic; using System.Linq; public static class DiffHelper { /// <summary> /// 生成array2的新增元素标记数组 /// </summary> /// <param name="array1">原始数组</param> /// <param name="array2">插入新增元素后的数组</param> /// <returns>和array2长度一致的标记数组,0=匹配原始序列,1=新增元素</returns> public static int[] GenerateInsertMarkArray(byte[] array1, byte[] array2) { int n = array1.Length; int m = array2.Length; int[] result = Enumerable.Repeat(1, m).ToArray(); // 默认全部标1,匹配到的再改0 // 计算编辑路径 var path = MyersDiff(array1, array2); // 回溯路径标记匹配位置 int x = n, y = m; foreach (var (dx, dy) in path.Reverse()) { if (dx == 1 && dy == 1) // 匹配步,对应位置标0 { result[y - 1] = 0; } x -= dx; y -= dy; } return result; } /// <summary> /// Myers差分算法核心实现,返回编辑路径 /// </summary> private static List<(int dx, int dy)> MyersDiff(byte[] a, byte[] b) { int n = a.Length; int m = b.Length; int max = n + m; int[] v = new int[2 * max + 2]; Array.Fill(v, -1); v[max + 1] = 0; // 存储每一步的v快照用于回溯 var vs = new List<int[]>(); int d; for (d = 0; d <= max; d++) { vs.Add((int[])v.Clone()); for (int k = -d; k <= d; k += 2) { int x; if (k == -d || (k != d && v[max + k - 1] < v[max + k + 1])) { x = v[max + k + 1]; } else { x = v[max + k - 1] + 1; } int y = x - k; while (x < n && y < m && a[x] == b[y]) { x++; y++; } v[max + k] = x; if (x >= n && y >= m) { // 回溯路径 var path = new List<(int dx, int dy)>(); for (int i = d; i >= 0; i--) { var prevV = vs[i]; int prevK = k; if (k == -i || (k != i && prevV[max + k - 1] < prevV[max + k + 1])) { prevK = k + 1; } else { prevK = k - 1; } int prevX = prevV[max + prevK]; int prevY = prevX - prevK; // 添加匹配步 while (x > prevX && y > prevY && a[x-1] == b[y-1]) { path.Add((1, 1)); x--; y--; } if (i > 0) { path.Add(x - prevX, y - prevY); } x = prevX; y = prevY; k = prevK; } return path; } } } return new List<(int dx, int dy)>(); } // 兼容int数组测试的重载 public static int[] GenerateInsertMarkArray(int[] array1, int[] array2) { return GenerateInsertMarkArray(array1.Select(i => (byte)i).ToArray(), array2.Select(i => (byte)i).ToArray()); } }
用法示例
public static void Main() { // 示例测试数据 int[] array1 = {1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 4, 5, 5, 5, 5, 5, 5, 6, 6, 7, 7, 7, 7, 8, 8, 9, 9, 0, 0, 0}; int[] array2 = {1, 1, 1, 2, 7, 7, 2, 2, 2, 2, 1, 2, 3, 2, 2, 3, 3, 4, 7, 2, 5, 5, 5, 5, 5, 5, 6, 6, 7, 7, 8, 4, 1, 1, 7, 7, 8, 8, 9, 9, 0, 0}; int[] array3 = DiffHelper.GenerateInsertMarkArray(array1, array2); // 输出标记数组,和需求示例完全一致 Console.WriteLine("array3: [{0}]", string.Join(", ", array3)); // 获取所有新增元素的索引,对应Beyond Compare右侧红色标记位置 List<int> insertIndexes = array3.Select((val, idx) => (val, idx)) .Where(t => t.val == 1) .Select(t => t.idx) .ToList(); Console.WriteLine("新增元素索引:[{0}]", string.Join(", ", insertIndexes)); }
内容的提问来源于stack exchange,提问作者JohnB
相关产品推荐
相关产品推荐

