如何在Groovy中按字段数字对类列表实现自定义自然排序?
实现特定规则的自然排序问题
需求说明
现有一个包含no和field字段的类列表:
[ no = '1', field = 'FEE_HIG_R_test1234_2', no = '2', field = 'FEE_HIG_R_test1234_11', no = '3', field = 'FEE_HIG_R_test1234_10', no = '4', field = 'FEE_HIG_R_test1234_1', no = '5', field = '06633-146944-0000036012', no = '6', field = '06633-155867-0000051910', no = '7', field = '06687-250844-00002544203' ]
需要按field字段实现以下排序规则:
- 优先级:以数字开头且包含连字符的字段(如
06633-...)排在FEE开头的字段之前 - 同一类字段内部,按数字自然排序(数字按数值大小比较,而非字符串字典序)
预期排序结果:
[ no = '5', field = '06633-146944-0000036012', no = '6', field = '06633-155867-0000051910', no = '7', field = '06687-250844-00002544203', no = '4', field = 'FEE_HIG_R_test1234_1', no = '1', field = 'FEE_HIG_R_test1234_2', no = '3', field = 'FEE_HIG_R_test1234_10', no = '2', field = 'FEE_HIG_R_test1234_11' ]
现有代码问题
原代码仅提取field中最后一段数字进行比较:
result.sort{ a,b -> (((a.field =~ /\d+/)[-1] as Integer) <=> ((b.field =~ /\d+/)[-1] as Integer)) }
存在两个核心问题:
- 未区分字段类型,导致
FEE开头的字段排在了数字连字符字段前面 - 仅用最后一段数字排序,无法覆盖数字连字符字段的完整自然排序需求(比如
06633-146944-0000036012需要按各段数字依次比较)
解决方案
分两步实现排序逻辑:先按字段类型确定优先级,再对同一类型的字段执行自然排序。
完整实现代码
// 定义自然排序的比较逻辑 def naturalCompare(String s1, String s2) { // 将字符串拆分为文字、数字交替的片段列表 def splitStr = { str -> str.split(/(?<=\D)(?=\d)|(?<=\d)(?=\D)/).collect { it.isNumber() ? it as Long : it.toLowerCase() } } def parts1 = splitStr(s1) def parts2 = splitStr(s2) // 逐段比较片段,找到第一个不同的位置返回结果 for (int i = 0; i < Math.min(parts1.size(), parts2.size()); i++) { def cmp = parts1[i] <=> parts2[i] if (cmp != 0) return cmp } // 所有片段相同时,短字符串排在前面 return parts1.size() <=> parts2.size() } // 执行排序 result.sort { a, b -> // 标记字段类型:数字连字符类型优先级为0,FEE类型为1 def typeA = a.field ==~ /^\d+-/ ? 0 : 1 def typeB = b.field ==~ /^\d+-/ ? 0 : 1 // 先比较类型优先级,类型相同则执行自然排序 typeA <=> typeB ?: naturalCompare(a.field, b.field) }
代码解释
- 类型优先级区分:通过正则
^\d+-识别数字连字符类型字段,赋予更高优先级(标记为0),确保这类字段排在前面 - 自然排序逻辑:
- 用正则拆分字符串为文字和数字片段(比如
FEE_HIG_R_test1234_10拆分为['fee_hig_r_test', 1234, '_', 10]) - 数字片段转为
Long按数值比较,文字片段转为小写按字典序比较 - 逐段对比片段,直到找到差异;若片段完全一致,短字符串排在前面
- 用正则拆分字符串为文字和数字片段(比如
运行上述代码后,列表将完全符合预期排序结果。
内容的提问来源于stack exchange,提问作者Alexandr Sova
相关产品推荐
相关产品推荐

