JavaScript自定义排序:实现A-Z循环分组排序需求
实现特定规则的JavaScript数组排序
需求说明
原数组:
[ 'B. Wound Bed', 'A. Wound Location and Measurements', 'D. Drainage', 'B. Wound Bed', 'C. Surrounding Tissue', 'Haroon Question Group Without Show PCP', 'D. Drainage', 'Haroon Question Group With Show PCP', 'A. Wound Location and Measurements', 'C. Surrounding Tissue', ];
预期排序结果:
[ 'A. Wound Location and Measurements', 'B. Wound Bed', 'C. Surrounding Tissue', 'D. Drainage', 'A. Wound Location and Measurements', 'B. Wound Bed', 'C. Surrounding Tissue', 'D. Drainage', 'Haroon Question Group With Show PCP', 'Haroon Question Group Without Show PCP' ]
排序规则:
- 优先按A-Z顺序完成完整一轮序列,即先依次排列一个A、B、C、D开头的元素
- 第一轮完成后,再从A-Z开始排列剩余的同类型元素
- 最后排列不以A-Z开头的元素,这部分按字符串自然排序
尝试的代码及问题
以下代码无法得到预期结果:
const arr = [ 'B. Wound Bed', 'A. Wound Location and Measurements', 'D. Drainage', 'B. Wound Bed', 'C. Surrounding Tissue', 'Haroon Question Group Without Show PCP', 'D. Drainage', 'Haroon Question Group With Show PCP', 'A. Wound Location and Measurements', 'C. Surrounding Tissue', ]; arr.sort((a, b) => { let aIndex = parseInt(a.charAt(0), 36); let bIndex = parseInt(b.charAt(0), 36); if (aIndex < bIndex) return -1; if (aIndex > bIndex) return 1; return 0; }); console.log(arr);
返回结果:
[ "A. Wound Location and Measurements", "A. Wound Location and Measurements", "B. Wound Bed", "B. Wound Bed", "C. Surrounding Tissue", "C. Surrounding Tissue", "D. Drainage", "D. Drainage", "Haroon Question Group Without Show PCP", "Haroon Question Group With Show PCP" ]
该代码会把相同字母开头的元素全部排在一起,不符合“先完成一轮A-Z再循环”的要求。
解决方案
实现思路
- 拆分数组:将原数组分为「A-Z开头的元素」和「非A-Z开头的元素」两类
- 处理A-Z类元素:统计每个字母的出现次数,然后按轮次依次取出每个字母的元素,直到所有元素都被排列
- 处理非A-Z类元素:直接按字符串自然排序
- 拼接两部分结果,得到最终排序数组
代码实现
const arr = [ 'B. Wound Bed', 'A. Wound Location and Measurements', 'D. Drainage', 'B. Wound Bed', 'C. Surrounding Tissue', 'Haroon Question Group Without Show PCP', 'D. Drainage', 'Haroon Question Group With Show PCP', 'A. Wound Location and Measurements', 'C. Surrounding Tissue', ]; // 1. 拆分数组 const letterGroups = {}; const nonLetterItems = []; arr.forEach(item => { const firstChar = item.charAt(0); if (/^[A-Z]$/.test(firstChar)) { if (!letterGroups[firstChar]) { letterGroups[firstChar] = []; } letterGroups[firstChar].push(item); } else { nonLetterItems.push(item); } }); // 2. 生成按轮次排列的A-Z元素序列 const sortedLetterItems = []; // 获取排序后的字母列表(A、B、C、D...) const sortedLetters = Object.keys(letterGroups).sort(); // 计算最大轮次:某个字母的最大出现次数 const maxRounds = Math.max(...Object.values(letterGroups).map(g => g.length)); // 按轮次遍历,每次取每个字母的对应位置元素 for (let round = 0; round < maxRounds; round++) { for (const letter of sortedLetters) { if (letterGroups[letter][round]) { sortedLetterItems.push(letterGroups[letter][round]); } } } // 3. 排序非A-Z元素 nonLetterItems.sort(); // 4. 拼接结果 const finalResult = [...sortedLetterItems, ...nonLetterItems]; console.log(finalResult);
代码说明
- 拆分数组时,用正则判断首字符是否为大写A-Z,将元素归类到对应字母的数组或非字母数组
- 统计每个字母的元素列表后,先对字母排序(保证A-Z顺序)
- 通过循环轮次,每次从每个字母的列表中取出第
round个元素,实现“一轮完整A-Z再循环”的效果 - 非字母元素直接调用
sort()做自然排序,符合预期中的顺序
运行上述代码即可得到目标排序结果。
内容的提问来源于stack exchange,提问作者Faizan Ahmad
相关产品推荐
相关产品推荐

