如何在JavaScript中对字符串+数字混合路径数组进行自然排序?
需求:对含数字的层级路径数组进行自然排序
示例输入
['/catalog/tag/categories/0', '/catalog/tag/categories/0/categories/0', '/catalog/tag/categories/0/categories/1', '/catalog/tag/categories/1', '/catalog/tag/categories/1/categories/0', '/catalog/tag/categories/1/categories/1', '/catalog/tag/categories/2', '/catalog/tag/categories/2/categories/0', '/catalog/tag/categories/2/categories/1', '/catalog/tag/categories/2/categories/10', '/catalog/tag/categories/2/categories/11', '/catalog/tag/categories/2/categories/14', '/catalog/tag/categories/2/categories/15', '/catalog/tag/categories/2/categories/16', '/catalog/tag/categories/2/categories/17', '/catalog/tag/categories/2/categories/2', '/catalog/tag/categories/2/categories/3', '/catalog/tag/categories/2/categories/7', '/catalog/tag/categories/2/categories/8', '/catalog/tag/categories/2/categories/9'];
期望输出
['/catalog/tag/categories/0', '/catalog/tag/categories/0/categories/0', '/catalog/tag/categories/0/categories/1', '/catalog/tag/categories/1', '/catalog/tag/categories/1/categories/0', '/catalog/tag/categories/1/categories/1', '/catalog/tag/categories/2', '/catalog/tag/categories/2/categories/0', '/catalog/tag/categories/2/categories/1', '/catalog/tag/categories/2/categories/2', '/catalog/tag/categories/2/categories/3', '/catalog/tag/categories/2/categories/7', '/catalog/tag/categories/2/categories/8', '/catalog/tag/categories/2/categories/9', '/catalog/tag/categories/2/categories/10', '/catalog/tag/categories/2/categories/11', '/catalog/tag/categories/2/categories/14', '/catalog/tag/categories/2/categories/15', '/catalog/tag/categories/2/categories/16', '/catalog/tag/categories/2/categories/17'];
Python可行实现
已通过以下Python代码实现需求:
import re def natural_sort(l): convert = lambda text: int(text) if text.isdigit() else text.lower() alphanum_key = lambda key: [convert(c) for c in re.split('([0-9]+)', key)] print(sorted(l, key=alphanum_key))
尝试的JavaScript代码(不符合预期)
以下JS代码排序结果不符合要求,会将同前缀的子路径排在父路径之后:
var reA = /[^a-zA-Z]/g; var reN = /[^0-9]/g; function sortAlphaNum(a, b) { var aA = a.replace(reA, ""); var bA = b.replace(reA, ""); if (aA === bA) { var aN = parseInt(a.replace(reN, ""), 10); var bN = parseInt(b.replace(reN, ""), 10); return aN === bN ? 0 : aN > bN ? 1 : -1; } else { return aA > bA ? 1 : -1; } } console.log(arr.sort(sortAlphaNum));
错误输出结果
['/catalog/tag/categories/0', '/catalog/tag/categories/1', '/catalog/tag/categories/2', '/catalog/tag/categories/0/categories/0', '/catalog/tag/categories/0/categories/1', '/catalog/tag/categories/1/categories/0', '/catalog/tag/categories/1/categories/1', '/catalog/tag/categories/2/categories/0', '/catalog/tag/categories/2/categories/1', '/catalog/tag/categories/2/categories/2', '/catalog/tag/categories/2/categories/3', '/catalog/tag/categories/2/categories/7', '/catalog/tag/categories/2/categories/8', '/catalog/tag/categories/2/categories/9', '/catalog/tag/categories/2/categories/10', '/catalog/tag/categories/2/categories/11', '/catalog/tag/categories/2/categories/14', '/catalog/tag/categories/2/categories/15', '/catalog/tag/categories/2/categories/16', '/catalog/tag/categories/2/categories/17'];
正确的JavaScript实现方案
借鉴Python的思路,实现支持任意层级路径的自然排序,同时保证父路径优先于子路径:
实现代码
function naturalSortPaths(arr) { // 转换函数:数字字符串转整数,其他转小写 const convert = text => text.match(/^\d+$/) ? parseInt(text, 10) : text.toLowerCase(); // 生成排序键:将路径按数字和非数字拆分,转换后得到数组 const getSortKey = path => path.split(/(\d+)/).map(convert); return arr.sort((a, b) => { const keyA = getSortKey(a); const keyB = getSortKey(b); // 逐段比较路径片段 for (let i = 0; i < Math.min(keyA.length, keyB.length); i++) { if (keyA[i] !== keyB[i]) { // 数字按大小比较,字符串按自然顺序比较 return typeof keyA[i] === 'number' ? keyA[i] - keyB[i] : keyA[i].localeCompare(keyB[i]); } } // 前缀完全相同时,短路径(父路径)排在前面 return keyA.length - keyB.length; }); } // 测试示例 const arr = ['/catalog/tag/categories/0', '/catalog/tag/categories/0/categories/0', '/catalog/tag/categories/0/categories/1', '/catalog/tag/categories/1', '/catalog/tag/categories/1/categories/0', '/catalog/tag/categories/1/categories/1', '/catalog/tag/categories/2', '/catalog/tag/categories/2/categories/0', '/catalog/tag/categories/2/categories/1', '/catalog/tag/categories/2/categories/10', '/catalog/tag/categories/2/categories/11', '/catalog/tag/categories/2/categories/14', '/catalog/tag/categories/2/categories/15', '/catalog/tag/categories/2/categories/16', '/catalog/tag/categories/2/categories/17', '/catalog/tag/categories/2/categories/2', '/catalog/tag/categories/2/categories/3', '/catalog/tag/categories/2/categories/7', '/catalog/tag/categories/2/categories/8', '/catalog/tag/categories/2/categories/9']; console.log(naturalSortPaths(arr));
代码说明
- convert函数:统一处理路径片段,数字转整数保证数值排序,非数字转小写保证大小写不敏感排序。
- getSortKey函数:用正则
/(\d+)/拆分路径,将每个数字和非数字部分单独提取,生成排序用的键数组。 - 排序逻辑:
- 逐段对比两个路径的键数组,数字直接比较大小,字符串用
localeCompare实现自然排序。 - 若前缀完全一致,短路径(父路径)优先于长路径(子路径),满足层级排序需求。
- 逐段对比两个路径的键数组,数字直接比较大小,字符串用
内容的提问来源于stack exchange,提问作者cfwithdecaf
相关产品推荐
相关产品推荐

