JS数组按升序值替换为对应索引问题及优化方案问询
解决数组元素替换为升序排列后对应索引的问题
问题根源
你遇到的问题本质是Array.indexOf()的局限性:它只会返回第一个匹配元素的索引,当数组存在重复值时,后续的重复元素会拿到错误的排名;如果元素值恰好等于某个索引值,还会和错误逻辑叠加导致结果混乱。
正确解决方案
核心思路是给每个元素绑定原始索引,排序后再根据原始索引映射回正确的排名,既能处理重复元素,也不会受元素值与索引值重合的影响。
代码实现
const nums = [32, -3, 62, 8, 121, -231, 62, 13]; // 1. 为每个元素绑定原始索引 const indexedElements = nums.map((value, originalIndex) => ({ value, originalIndex })); // 2. 按元素值升序排序 indexedElements.sort((a, b) => a.value - b.value); // 3. 生成结果数组:根据原始索引填充对应的排名(排序后的位置) const result = new Array(nums.length); indexedElements.forEach((element, rank) => { result[element.originalIndex] = rank; }); console.log(result); // 输出:[4, 1, 5, 2, 7, 0, 6, 3]
测试问题数组
针对你提到的错误示例数组[32, -3, 62, 7, 121, -231, 62, 13, 0],运行上述代码会得到正确结果:
console.log(result); // 输出:[5, 1, 6, 3, 8, 0, 7, 4, 2]
其中-231对应的排名为0,完全符合预期。
原方案的修复思路(仅限特定场景)
如果坚持使用基于indexOf的逻辑,需要处理重复元素,但这种方式仅适用于允许重复值共享同一排名的场景,不符合你的示例要求:
const nums = [32, -3, 62, 8, 121, -231, 62, 13]; const sorted = [...nums].sort((a, b) => a - b); // 创建值到排名的映射,跳过已处理的重复值 const rankMap = new Map(); sorted.forEach((val, idx) => { if (!rankMap.has(val)) { rankMap.set(val, idx); } }); // 生成结果(重复值会共享同一排名) const result = nums.map(val => rankMap.get(val));
注意:此方式会让示例中的两个62都返回5,不符合你需要的5和6的区分结果,因此第一种方案是最优解。
内容的提问来源于stack exchange,提问作者Herbie Vine
相关产品推荐
相关产品推荐

