JavaScript:如何实现可变长度分数数组的多维度升序排序?
如何按可变长度的分数数组依次升序排序(缺失元素视为无穷大)
首先来看你的需求:你需要对一个包含标签和可变长度分数数组的列表进行排序,排序规则是按分数数组的元素依次升序比较,缺失的元素视为无穷大(排在末尾)。下面分两种方案来实现——原生JavaScript和Lodash,同时解答你的疑问:
问题回顾
先明确你的输入和预期输出:
输入数组
[ ["Label6", [1]], ["Label5", [1,5]], ["Label2", [0,1,3,5]], ["Label1", [0,1,2]], ["Label3", [0,1,4]], ["Label4", [1,4]] ]
预期排序结果
[ ["Label1", [0,1,2]], ["Label2", [0,1,3,5]], ["Label3", [0,1,4]], ["Label4", [1,4]], ["Label5", [1,5]], ["Label6", [1]] ]
解决方案
一、原生JavaScript实现(无需依赖)
原生ES6并没有直接提供类似Ruby list.sort_by(&:last)的sortBy方法,但我们可以利用数组的sort()方法,传入自定义的比较函数来实现需求,逻辑非常直观:
const options = [ ["Label6", [1]], ["Label5", [1,5]], ["Label2", [0,1,3,5]], ["Label1", [0,1,2]], ["Label3", [0,1,4]], ["Label4", [1,4]] ]; // 先复制原数组避免修改原数据,然后排序 const sortedOptions = [...options].sort((a, b) => { const scoresA = a[1]; const scoresB = b[1]; // 取两个分数数组的最大长度,确保遍历到所有需要比较的位置 const maxLength = Math.max(scoresA.length, scoresB.length); for (let i = 0; i < maxLength; i++) { // 数组越界时用Infinity替代,保证缺失元素排在末尾 const valA = scoresA[i] ?? Infinity; const valB = scoresB[i] ?? Infinity; // 找到第一个不相等的元素,直接返回差值实现升序 if (valA !== valB) { return valA - valB; } } // 兜底逻辑:如果所有对应元素都相等,长度短的排在后面(其实上面的Infinity已经处理了,这里是冗余但安全的写法) return scoresA.length - scoresB.length; }); console.log(sortedOptions);
核心逻辑说明:
- 遍历两个分数数组的每个索引位置,依次比较对应元素
- 当某个索引超出数组长度时,用
Infinity替代(升序排序中Infinity会被排在最后) - 一旦找到第一个不相等的元素,立即返回比较结果,停止后续遍历
- 用扩展运算符
[...options]复制原数组,避免排序时修改原数据
二、使用Lodash实现
如果你已经在项目中使用Lodash,可以利用它的sortBy方法,但需要做一点小处理——因为默认情况下sortBy会把undefined(数组越界时的值)排在前面,不符合我们的需求,所以要把缺失的元素转换成Infinity:
const _ = require('lodash'); const options = [ ["Label6", [1]], ["Label5", [1,5]], ["Label2", [0,1,3,5]], ["Label1", [0,1,2]], ["Label3", [0,1,4]], ["Label4", [1,4]] ]; // 先获取所有分数数组的最大长度,确定需要比较的维度 const maxScoreLength = _.maxBy(options, item => item[1].length)[1].length; // 为每个维度生成一个迭代函数,把缺失元素转为Infinity const sortKeys = Array.from({ length: maxScoreLength }, (_, index) => { return item => item[1][index] ?? Infinity; }); // 用Lodash的sortBy依次按每个维度排序 const sortedOptions = _.sortBy(options, ...sortKeys); console.log(sortedOptions);
逻辑说明:
- 先找到最长的分数数组长度,确定需要比较多少个维度
- 为每个维度生成一个迭代函数,返回对应位置的元素或
Infinity - 把这些迭代函数传入
sortBy,它会按顺序依次进行排序,完美匹配你的需求
疑问解答
- 原生ES6没有直接的
sortBy方法可以完全替代Ruby的list.sort_by(&:last),但通过Array.sort()自定义比较函数可以轻松实现需求,而且不需要额外依赖。 - Lodash/Underscore的
sortBy可以实现类似效果,但需要针对缺失元素做特殊处理,把undefined转为Infinity,否则排序结果会不符合预期。
内容的提问来源于stack exchange,提问作者Cyril Duchon-Doris
相关产品推荐
相关产品推荐

