如何精准查找两个Java List之间的内容差异?
问题根源
你当前的实现存在两个核心问题:
- 分词规则不合理:按
\s+空格拆分时,标点会和相邻单词绑定为同一个元素,导致s2中的match.和s1中的match被判定为完全不同的元素,无法拆分出末尾的.差异。 removeAll逻辑不匹配需求:该方法是无顺序的集合差集计算,只会完全删除s1中存在的元素,既不识别元素顺序,也无法提取元素内部的局部差异,只要两个元素不完全相等就会整体保留。
解决方案
根据你的需求可以选择两种实现路径:
路径1:字符级差异提取(直接得到你期望的!和.结果)
直接逐字符对比两个字符串,过滤空格后即可得到精准的差异字符:
public List<Character> getCharLevelDiff(String s1, String s2) { List<Character> diffs = new ArrayList<>(); int maxLen = Math.max(s1.length(), s2.length()); for (int i = 0; i < maxLen; i++) { char c1 = i < s1.length() ? s1.charAt(i) : Character.MIN_VALUE; char c2 = i < s2.length() ? s2.charAt(i) : Character.MIN_VALUE; if (c1 != c2 && !Character.isWhitespace(c2)) { diffs.add(c2); } } return diffs; }
路径2:保留列表对比逻辑,适配顺序敏感的差异识别
如果后续需要保持按语义单元拆分对比的能力,先优化分词规则把标点拆分为独立元素,再用文本diff标准的最长公共子序列(LCS)算法做顺序敏感的差异计算:
// 优化分词:把单词、标点分别拆为独立列表元素 private List<String> splitWithPunctuation(String s) { List<String> tokens = new ArrayList<>(); Matcher matcher = Pattern.compile("\\w+|[^\\w\\s]").matcher(s); while (matcher.find()) { tokens.add(matcher.group()); } return tokens; } // 基于LCS的顺序敏感列表差异计算,返回s2相对s1的新增内容 public <T> List<T> sequenceDiff(List<T> s2, List<T> s1) { int n = s1.size(), m = s2.size(); int[][] dp = new int[n + 1][m + 1]; // 构建LCS动态规划表 for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { if (s1.get(i - 1).equals(s2.get(j - 1))) { dp[i][j] = dp[i - 1][j - 1] + 1; } else { dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]); } } } // 回溯提取差异 List<T> diffs = new ArrayList<>(); int i = n, j = m; while (i > 0 && j > 0) { if (s1.get(i - 1).equals(s2.get(j - 1))) { i--; j--; } else if (dp[i - 1][j] > dp[i][j - 1]) { i--; } else { diffs.add(s2.get(j - 1)); j--; } } while (j > 0) { diffs.add(s2.get(j - 1)); j--; } Collections.reverse(diffs); return diffs; }
调用时先用splitWithPunctuation拆分s1、s2得到两个列表,再传入sequenceDiff即可得到!和.的预期结果。
内容的提问来源于stack exchange,提问作者Beginner
相关产品推荐
相关产品推荐

