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

如何对Java对象多字段进行自然排序?解决字母数字名称排序问题

解决字母数字类型Item Name的自然排序问题

你当前的排序代码如下:

Comparator<Item> itemComparator = Comparator.comparing(Item::getListId)
                                           .thenComparing(Item::getItemName);
Collections.sort(itemList, itemComparator);

这段代码能按listId完成分组排序,但itemName属于字母数字组合(如Item 0、Item 101),默认字符串排序基于ASCII码,会出现数字逻辑顺序错误的情况(比如Item 0 → Item 101 → Item 28)。以下是几种简便的实现自然排序(数字按数值大小排序)的方案:

方案一:针对固定格式的快速实现

如果你的itemName格式固定为[前缀] [数字](比如示例中的Item XXX),可以直接提取数字部分转为整数作为排序依据,代码简洁高效:

Comparator<Item> itemComparator = Comparator.comparing(Item::getListId)
                                           .thenComparing(item -> {
                                               // 拆分名称提取数字段
                                               String numSegment = item.getItemName().split(" ")[1];
                                               return Integer.parseInt(numSegment);
                                           });
Collections.sort(itemList, itemComparator);

方案二:通用自然排序(无第三方依赖)

如果itemName格式不固定(前缀、数字位置可能变化),可以实现一个通用的自然排序比较器,兼容任意包含数字的字符串:

// 通用自然字符串比较器
Comparator<String> naturalStringComparator = (s1, s2) -> {
    int idx1 = 0, idx2 = 0;
    while (idx1 < s1.length() && idx2 < s2.length()) {
        if (Character.isDigit(s1.charAt(idx1)) && Character.isDigit(s2.charAt(idx2))) {
            // 提取连续数字序列并转为数值比较
            long num1 = 0, num2 = 0;
            while (idx1 < s1.length() && Character.isDigit(s1.charAt(idx1))) {
                num1 = num1 * 10 + (s1.charAt(idx1) - '0');
                idx1++;
            }
            while (idx2 < s2.length() && Character.isDigit(s2.charAt(idx2))) {
                num2 = num2 * 10 + (s2.charAt(idx2) - '0');
                idx2++;
            }
            if (num1 != num2) {
                return Long.compare(num1, num2);
            }
        } else {
            if (s1.charAt(idx1) != s2.charAt(idx2)) {
                return Character.compare(s1.charAt(idx1), s2.charAt(idx2));
            }
            idx1++;
            idx2++;
        }
    }
    return Integer.compare(s1.length(), s2.length());
};

// 应用到Item排序
Comparator<Item> itemComparator = Comparator.comparing(Item::getListId)
                                           .thenComparing(Item::getItemName, naturalStringComparator);
Collections.sort(itemList, itemComparator);

方案三:借助第三方库简化代码

如果项目已引入Apache Commons Lang库,可直接使用内置的自然排序方法,代码最简洁:

import org.apache.commons.lang3.StringUtils;

Comparator<Item> itemComparator = Comparator.comparing(Item::getListId)
                                           .thenComparing(Item::getItemName, StringUtils::naturalCompare);
Collections.sort(itemList, itemComparator);

根据你提供的JSON示例数据,itemName格式固定,使用方案一即可满足需求,得到listId分组后,itemName按数字从小到大排列的结果。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 11:43:14