Javascript 基于双字段排序对象数组并重置order属性实现方案
需求说明
我们需要对一组对象数组按照以下规则排序并修改元素的order属性:
- 所有
relativePosition为Before的元素排在After元素之前 - 同一
mdmStep分类下,Before类元素的order从1开始顺序递增,After类元素的order单独从1开始重新顺序递增
现有错误代码
const data = [{ "id": 0, "mdmStep": { "name": "Insert to Stage", "id": 1 }, "relativePosition": { "name": "After", "id": 2 }, "order": 1, "details": [{ "commandText": "SELECT * FROM MDSRC_PRO_KOMODO_TRAN" }] }, { "id": 3, "mdmStep": { "name": "Insert to Stage", "id": 1 }, "relativePosition": { "name": "Before", "id": 1 }, "order": 4, "details": [{ "commandText": "SELECT * FROM MDSRC_PRO_KOMODO_CONFIG" }] }, { "id": 1, "mdmStep": { "name": "Insert to Stage", "id": 1 }, "relativePosition": { "name": "After", "id": 2 }, "order": 2, "details": [{ "commandText": "SELECT * FROM MDSRC_PRO_KOMODO_ADDR" }] }, { "id": 2, "mdmStep": { "name": "Insert to Raw", "id": 2 }, "relativePosition": { "name": "After", "id": 2 }, "order": 3, "details": [{ "commandText": "SELECT * FROM MDSRC_PRO_KOMODO_ADDR" }] }, { "id": 4, "mdmStep": { "name": "Insert to Raw", "id": 2 }, "relativePosition": { "name": "After", "id": 2 }, "order": 5, "details": [{ "commandText": "SELECT * FROM MDSRC_PRO_KOMODO_CONFIG" }] }, { "id": 5, "mdmStep": { "name": "Update Match Fields", "id": 5 }, "relativePosition": { "name": "Before", "id": 1 }, "order": 6, "details": [{ "commandText": "HELLO ARUN" }] } ] const groups = _.groupBy(data, 'mdmStep.name') const groupValues = _.reduce(_.keys(groups), (a, c) => { a[c] = _.orderBy(groups[c], 'relativePosition.id').map((i, idx) => { if (i.relativePosition.id === 1) { return { ...i, order: idx } } return { ...i, order: idx } }); return a }, {}) const changeOrders = _.orderBy(_.flattenDeep((_.map(_.keys(groupValues), group => { return _.map(groupValues[group], (i, index) => { return { ...i, order: index || index + 1 } }) }))), 'mdmStep.id') console.log(changeOrders)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js"></script>
预期输出
[ { "id": 3, "mdmStep": { "name": "Insert to Stage", "id": 1 }, "relativePosition": { "name": "Before", "id": 1 }, "order": 1, "details": [ { "commandText": "SELECT * FROM MDSRC_PRO_KOMODO_CONFIG" } ] }, { "id": 0, "mdmStep": { "name": "Insert to Stage", "id": 1 }, "relativePosition": { "name": "After", "id": 2 }, "order": 1, "details": [ { "commandText": "SELECT * FROM MDSRC_PRO_KOMODO_TRAN" } ] }, { "id": 1, "mdmStep": { "name": "Insert to Stage", "id": 1 }, "relativePosition": { "name": "After", "id": 2 }, "order": 2, "details": [ { "commandText": "SELECT * FROM MDSRC_PRO_KOMODO_ADDR" } ] }, { "id": 2, "mdmStep": { "name": "Insert to Raw", "id": 2 }, "relativePosition": { "name": "After", "id": 2 }, "order": 1, "details": [ { "commandText": "SELECT * FROM MDSRC_PRO_KOMODO_ADDR" } ] }, { "id": 4, "mdmStep": { "name": "Insert to Raw", "id": 2 }, "relativePosition": { "name": "After", "id": 2 }, "order": 2, "details": [ { "commandText": "SELECT * FROM MDSRC_PRO_KOMODO_CONFIG" } ] }, { "id": 5, "mdmStep": { "name": "Update Match Fields", "id": 5 }, "relativePosition": { "name": "Before", "id": 1 }, "order": 1, "details": [ { "commandText": "HELLO ARUN" } ] } ]
问题排查与正确实现
原有代码问题
- 分组内赋值order时没有区分Before和After的独立计数序列,直接用全局索引赋值,导致After的计数没有从1重新开始
- 最后二次修改order的逻辑错误覆盖了分组内的赋值结果,分组逻辑用name而非id作为键也存在潜在的重复风险
正确实现代码
const result = _(data) // 按mdmStep.id分组,同分类元素聚合 .groupBy('mdmStep.id') // 所有分组按mdmStep.id升序排列 .orderBy(group => group[0].mdmStep.id) // 遍历每个分组处理排序和order赋值 .flatMap(group => { // 组内先按relativePosition.id升序,保证Before在前 const sortedInGroup = _.orderBy(group, 'relativePosition.id') let beforeCount = 1 let afterCount = 1 return sortedInGroup.map(item => { const newItem = {...item} // 分别维护Before和After的计数 if (item.relativePosition.id === 1) { newItem.order = beforeCount++ } else { newItem.order = afterCount++ } return newItem }) }) .value() console.log(result)
运行上述代码即可得到完全符合要求的输出结果。
内容的提问来源于stack exchange,提问作者arunmmanoharan
相关产品推荐
相关产品推荐

