JS如何根据另一对象数组顺序排序目标对象数组(含重复键)
按指定数组顺序匹配重名元素排序实现
现有数据结构
两个对象数组定义如下:
const array1 = [ { "name": "B", "order": 1 }, { "name": "C", "order": 2 }, { "name": "D", "order": 3 }, { "name": "B", "order": 4 }, { "name": "A", "order": 5 } ] const array2 = [ { "name": "B", "order": 1, "id": 3638 }, { "name": "B", "order": 1, "id": 3661 }, { "name": "C", "order": 2, "id": 3658 }, { "name": "D", "order": 3, "id": 3659 }, { "name": "A", "order": 5, "id": 3636 } ]
需求说明
需要基于name属性对array2排序,使其元素顺序和array1完全匹配:
array1中第一个name为B的元素在索引0位置,第二个name为B的元素在索引3位置array2中两个name为B的元素最终也要分别落在索引0、索引3的位置,不能相邻排列
无效方案说明
以下两种实现均无法达到预期效果:
// 方案1 array2.sort((a, b) => array1.indexOf(a.name) - array1.indexOf(b.name)); // 方案2 let sorted = array2.sort((a, b) => { return array1.findIndex(p => p.name=== a.name) - array1.findIndex(p => p.name=== b.name); });
失效原因:indexOf和findIndex遇到重名值时,只会返回第一个匹配项的索引。两个B元素计算出的排序权重完全相同,排序时不会被拆分到不同位置,无法匹配预期顺序。
可行实现
核心逻辑是按顺序消耗array1的name匹配位,每匹配到一个重名元素就标记对应位置为已使用,避免后续重名元素重复匹配到同一个索引:
// 生成待匹配的name顺序队列 const matchQueue = array1.map(item => item.name); const sortedArray2 = array2 .map(item => { // 查找当前元素在队列中第一个未被使用的匹配位置 const weight = matchQueue.indexOf(item.name); // 标记该位置已被占用 matchQueue[weight] = Symbol('used'); return { ...item, weight }; }) // 按匹配到的权重排序 .sort((a, b) => a.weight - b.weight) // 移除临时添加的权重字段 .map(({ weight, ...item }) => item);
执行后得到的sortedArray2顺序为:
{name: "B", order: 1, id: 3638}(匹配array1索引0的B){name: "C", order: 2, id: 3658}(匹配array1索引1的C){name: "D", order: 3, id: 3659}(匹配array1索引2的D){name: "B", order: 1, id: 3661}(匹配array1索引3的B){name: "A", order: 5, id: 3636}(匹配array1索引4的A)
完全符合预期顺序要求。
内容的提问来源于stack exchange,提问作者André Castro
相关产品推荐
相关产品推荐

