You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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字段实现以下排序规则:

  1. 优先级:以数字开头且包含连字符的字段(如06633-...)排在FEE开头的字段之前
  2. 同一类字段内部,按数字自然排序(数字按数值大小比较,而非字符串字典序)

预期排序结果:

[
    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)
}

代码解释

  1. 类型优先级区分:通过正则^\d+-识别数字连字符类型字段,赋予更高优先级(标记为0),确保这类字段排在前面
  2. 自然排序逻辑:
    • 用正则拆分字符串为文字和数字片段(比如FEE_HIG_R_test1234_10拆分为['fee_hig_r_test', 1234, '_', 10])
    • 数字片段转为Long按数值比较,文字片段转为小写按字典序比较
    • 逐段对比片段,直到找到差异;若片段完全一致,短字符串排在前面

运行上述代码后,列表将完全符合预期排序结果。

内容的提问来源于stack exchange,提问作者Alexandr Sova

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 04:15:05