为何ArrayList排序后10q在前列?如何让它排在9v之后?
解决Java字符串排序中数字部分按数值排序的问题
问题原因
默认的Collections.sort()采用字典序排序字符串。对于"10q"和"1g",逐字符对比时:第一个字符都是'1',第二个字符'0'的ASCII码(48)远小于'g'的ASCII码(103),所以"10q"会排在"1g"前面,而非按数字10和1的数值大小排序。
解决方案
方案一:自定义比较器(推荐,适配任意数字范围)
重写排序逻辑,先提取字符串中的数字部分转为整数,按数值大小排序;数字相同时再比较字符部分。
修改排序代码如下:
Collections.sort(list, (s1, s2) -> { // 提取字符串中的数字部分并转为整数 int num1 = Integer.parseInt(s1.replaceAll("\\D", "")); int num2 = Integer.parseInt(s2.replaceAll("\\D", "")); // 先比较数字大小 int numCompare = Integer.compare(num1, num2); if (numCompare != 0) { return numCompare; } // 数字相同则比较字符部分 char char1 = s1.replaceAll("\\d", "").charAt(0); char char2 = s2.replaceAll("\\d", "").charAt(0); return Character.compare(char1, char2); });
方案二:补前导零(简单,适合数字范围明确的场景)
存储字符串时,将数字格式化为固定长度的字符串(比如两位),补前导零,这样字典序排序就和数值顺序一致。
修改添加元素的代码:
// 用String.format把数字转为两位带前导零的字符串 list.add(String.format("%02d%c", indices[j], ch[i]));
排序后列表会是[00q, 01g, 02d, 03x, 04e, 05t, 06w, 07c, 08t, 09v, 10q],后续拼接字符串时replaceAll("\\d", "")依然能正确去掉所有数字,不影响最终结果。
完整示例代码(方案一)
import java.util.ArrayList; import java.util.Collections; public class SortFixExample { public static void main(String[] args) { String s = "vttqexwqgdc"; char[] ch = s.toCharArray(); int[] indices = {9, 5, 8, 0, 4, 3, 6, 10, 1, 2, 7}; ArrayList<String> list = new ArrayList<>(); for (int i = 0, j = 0; i < ch.length; i++, j++) { list.add(indices[j] + "" + ch[i]); } // 自定义排序逻辑 Collections.sort(list, (s1, s2) -> { int num1 = Integer.parseInt(s1.replaceAll("\\D", "")); int num2 = Integer.parseInt(s2.replaceAll("\\D", "")); int numComp = Integer.compare(num1, num2); return numComp != 0 ? numComp : Character.compare(s1.replaceAll("\\d", "").charAt(0), s2.replaceAll("\\d", "").charAt(0)); }); System.out.println(list); // 输出 [0q, 1g, 2d, 3x, 4e, 5t, 6w, 7c, 8t, 9v, 10q] String str = ""; for (String value : list) { str += value; } str = str.replaceAll("\\d", ""); System.out.println(str); } }
内容的提问来源于stack exchange,提问作者sharforaz rahman
相关产品推荐
相关产品推荐

