如何高效检测ArrayList中存在指定索引值相同但补充索引值不同的元组?
解决方案:放弃正则,用Java Streams实现高效检测
首先直接给结论:你没法用正则表达式直接实现这个需求,因为正则的核心是字符串模式匹配,而你的需求本质是「按指定维度分组后,检查组内是否存在不同的补充维度值」——这种带有逻辑关联和分组对比的需求,正则根本无法表达,强行写出来也会极度复杂、难以维护,而且性能不会比你原来的方法好。
你的原始方法用双重循环+正则,时间复杂度是O(n²),数据量一大就会卡顿,而用Java Streams结合分组的方式可以把时间复杂度降到O(n),同时逻辑清晰很多。
为什么正则不行?
你需要的是:
- 找到所有在指定索引上值相同的行
- 检查这些行中是否有至少两行在补充索引上值不同
正则只能做「匹配符合某个模式的字符串」,但它没办法在匹配的同时,把匹配到的字符串和原字符串的补充索引值做对比,更没办法自动分组并检查组内的差异。即使你硬凑出一个正则,也会因为需要包含所有可能的组合而变得无比冗长,完全不具备实用性。
用Java Streams的高效实现
核心思路是:按指定索引的值对行进行分组,然后检查每个分组内的补充索引值是否不唯一。如果存在这样的分组,就说明满足你的条件。
实现代码(简洁版)
import java.util.ArrayList; import java.util.List; import java.util.stream.Collectors; public class MatchingChecker { public boolean checkMatching() { ArrayList<String> rows = new ArrayList<>(); rows.add("7,2,2,1,1"); rows.add("7,3,2,1,1"); rows.add("7,8,1,1,1"); rows.add("8,2,1,3,1"); rows.add("8,2,1,4,1"); rows.add("8,4,5,1,1"); int[] indices = new int[]{2, 3}; int supplementaryIndex = 1; return rows.stream() // 把每行分割成字符串数组,方便取对应索引的值 .map(row -> row.split(",")) // 按指定索引的值分组,key是指定索引值的列表;同时收集每组的补充索引值到Set中(自动去重) .collect(Collectors.groupingBy( parts -> { // 构建分组key:取出指定索引的所有值组成List List<String> keyParts = new ArrayList<>(); for (int idx : indices) { keyParts.add(parts[idx]); } return keyParts; }, Collectors.mapping(parts -> parts[supplementaryIndex], Collectors.toSet()) )) // 检查是否有任何一个分组的补充索引值集合大小>1(说明存在不同的值) .values() .stream() .anyMatch(set -> set.size() > 1); } }
代码解释
- 分割每行:用
map(row -> row.split(","))把每行字符串转成数组,方便快速获取任意索引的值。 - 分组逻辑:
- 分组的key是指定索引对应的所有值组成的List,这样所有在指定索引上值相同的行会被分到同一组。
- 分组时直接收集每组的补充索引值到
Set中,Set会自动去重,所以如果组内有不同的补充索引值,Set的大小就会大于1。
- 检查条件:用
anyMatch(set -> set.size() > 1)判断是否存在符合条件的分组,一旦找到就立即返回true,无需遍历所有分组。
性能优势
这个方法的时间复杂度是O(n),因为只需要遍历两次数据:一次分组,一次检查分组。相比你原来的O(n²)双重循环,数据量越大,性能提升越明显。而且内存占用也更低,因为分组时只存储了必要的key和补充索引值集合,不需要存储整个行数据。
扩展:处理任意数量的指定索引
上面的代码已经支持任意长度的indices数组,不管你指定1个还是多个索引,分组逻辑都能正常工作,不需要修改核心代码。
内容的提问来源于stack exchange,提问作者Stefano
相关产品推荐
相关产品推荐

