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

如何在Kotlin中按数字而非字典序排序字母数字字符串?

Kotlin 实现自定义列表排序

默认的sort()方法采用字典序排序,所以会出现"10"排在"2"前、"A10"排在"A2"前的情况,这不符合你需要的纯数字按数值升序在前,字母开头的字符串按前缀字母升序+后续数字自然排序的需求。

解决方案:自定义比较器

通过实现Comparator来定义排序规则,核心逻辑是:

  • 纯数字字符串优先排在前面,且按数值大小升序
  • 非数字字符串先按前缀字母升序,前缀相同则纯字母排在带数字的前面,带数字的按数字数值升序

完整代码实现

// 存储拆分后的字符串部分:前缀(字母/非数字)、数字部分(如果有)
data class StringPart(val prefix: String, val number: Long?)

// 拆分字符串为前缀和数字部分的辅助函数
fun splitString(s: String): StringPart {
    val firstDigitIndex = s.indexOfFirst { it.isDigit() }
    return when {
        // 纯数字开头
        firstDigitIndex == 0 -> {
            val lastDigitIndex = s.indexOfLast { it.isDigit() }
            StringPart("", s.substring(0, lastDigitIndex + 1).toLong())
        }
        // 无数字,纯字母/其他字符
        firstDigitIndex == -1 -> StringPart(s, null)
        // 前缀为字母,后面带数字
        else -> {
            val prefix = s.substring(0, firstDigitIndex)
            val lastDigitIndex = s.indexOfLast { it.isDigit() }
            val numStr = s.substring(firstDigitIndex, lastDigitIndex + 1)
            StringPart(prefix, numStr.toLong())
        }
    }
}

// 自定义排序比较器
val customSortComparator = Comparator<String> { a, b ->
    val partA = splitString(a)
    val partB = splitString(b)

    val isANumber = partA.prefix.isEmpty() && partA.number != null
    val isBNumber = partB.prefix.isEmpty() && partB.number != null

    when {
        // 数字排在非数字前面
        isANumber && !isBNumber -> -1
        !isANumber && isBNumber -> 1
        // 两个都是数字,按数值比较
        isANumber && isBNumber -> partA.number!!.compareTo(partB.number!!)
        // 非数字情况,先比前缀
        else -> {
            val prefixCompare = partA.prefix.compareTo(partB.prefix)
            if (prefixCompare != 0) {
                prefixCompare
            } else {
                // 前缀相同,纯字母排在带数字的前面,数字按数值比较
                when {
                    partA.number == null && partB.number == null -> 0
                    partA.number == null -> -1
                    partB.number == null -> 1
                    else -> partA.number.compareTo(partB.number)
                }
            }
        }
    }
}

// 测试排序
fun main() {
    val list = mutableListOf("1", "2", "10", "A10", "A1", "A2", "B24C", "A")
    list.sortWith(customSortComparator)
    println(list) // 输出:[1, 2, 10, A, A1, A2, A10, B24C]
}

逻辑说明

  1. 字符串拆分:将每个字符串拆分为前缀(字母或非数字部分)和数字部分(如果存在),方便后续比较。
  2. 优先级判断:纯数字字符串优先级最高,直接排在非数字字符串前面。
  3. 同类型比较:
    • 纯数字之间按数值大小升序,避免字典序的问题。
    • 非数字字符串先比较前缀字母,前缀相同则纯字母项排在带数字项前面,带数字项按数字数值升序排列。

内容的提问来源于stack exchange,提问作者Benjamin Ting

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.01 20:52:43