有条件地合并对象数组
Conditionally merge array of objects
我正在寻找一种优雅的方式(最好是不可变的,lodash - 好的)来有条件地压缩数组。
我想检查 section
和 path
值组合的重复项,并附加这些重复项的 ids
。
所以给出
const arrayToBeCompacted = [
{
section: "Section name 1",
path: ["segment1", "segment2"],
ids: ["id1"]
},
{
section: "Section name 1",
path: ["segment1", "segment2"],
ids: ["id2"]
},
{
section: "Section name2",
path: ["segment1", "segment2"],
ids: ["id3"]
},
{
section: "Another section",
path: ["segment1", "segment2"],
ids: ["id4"]
},
{
section: "Another section",
path: ["segment1", "segment2"],
ids: ["id5"]
},
]
结果我想要
const resultingArray = [
{
section: "Section name 1",
path: ["segment1", "segment2"],
ids: ["id1", "id2"]
},
{
section: "Section name 2",
path: ["segment1", "segment2"],
ids: ["id3"]
},
{
section: "Another section",
path: ["segment1", "segment2"],
ids: ["id4", "id5"]
},
]
似乎 lodash.uniq(By, With)
和 lodash.union(By, With)
不是我要找的。
你可以用 reduce 做到这一点
const arrayToBeCompacted = [
{
section: "Section name 1",
path: ["segment1", "segment2"],
ids: ["id1"]
},
{
section: "Section name 1",
path: ["segment1", "segment2"],
ids: ["id2"]
},
{
section: "Section name2",
path: ["segment1", "segment2"],
ids: ["id3"]
},
{
section: "Another section",
path: ["segment1", "segment2"],
ids: ["id4"]
},
{
section: "Another section",
path: ["segment1", "segment2"],
ids: ["id5"]
},
]
const compacted = Object.values(arrayToBeCompacted.reduce((res, {section, path, ids}) => {
const key = section + path.join('|')
const existing = res[key] || {ids: [], section, path}
existing.ids = [...existing.ids, ...ids]
res[key] = existing
return res
}, {}))
console.log(compacted)
以下是实现目标的一种可能方法。
代码段
// method to compact array of objects
const compactArr = arr => (
Object.values( // extract values from intermediate result-obj
arr.reduce( // iterate over the array using "reduce"
(acc, itm) => { // "acc" is the accumuator/aggregator
const {section, ids, path} = itm; // de-structure to get props
// construct uniq-key using "section" and "path"
const uniqKey = `${section}-${path.join('-')}`;
acc[uniqKey] = {
...(acc[uniqKey] || {}),
section, path, // if "section" already exists, concat "ids"
ids: (acc[uniqKey]?.ids ?? []).concat(ids)
}
return acc;
},
{} // initial value of "acc" is empty-object {}
)
) // implicit return from method
);
const arrayToBeCompacted = [{
section: "Section name 1",
path: ["segment1", "segment2"],
ids: ["id1"]
},
{
section: "Section name 1",
path: ["segment1", "segment2"],
ids: ["id2"]
},
{
section: "Section name2",
path: ["segment1", "segment2"],
ids: ["id3"]
},
{
section: "Another section",
path: ["segment1", "segment2"],
ids: ["id4"]
},
{
section: "Another section",
path: ["segment1", "segment2"],
ids: ["id5"]
},
];
console.log('compacted array: ', compactArr(arrayToBeCompacted));
.as-console-wrapper { max-height: 100% !important; top: 0 }
说明
在上面的代码片段中添加了内联评论。
我正在寻找一种优雅的方式(最好是不可变的,lodash - 好的)来有条件地压缩数组。
我想检查 section
和 path
值组合的重复项,并附加这些重复项的 ids
。
所以给出
const arrayToBeCompacted = [
{
section: "Section name 1",
path: ["segment1", "segment2"],
ids: ["id1"]
},
{
section: "Section name 1",
path: ["segment1", "segment2"],
ids: ["id2"]
},
{
section: "Section name2",
path: ["segment1", "segment2"],
ids: ["id3"]
},
{
section: "Another section",
path: ["segment1", "segment2"],
ids: ["id4"]
},
{
section: "Another section",
path: ["segment1", "segment2"],
ids: ["id5"]
},
]
结果我想要
const resultingArray = [
{
section: "Section name 1",
path: ["segment1", "segment2"],
ids: ["id1", "id2"]
},
{
section: "Section name 2",
path: ["segment1", "segment2"],
ids: ["id3"]
},
{
section: "Another section",
path: ["segment1", "segment2"],
ids: ["id4", "id5"]
},
]
似乎 lodash.uniq(By, With)
和 lodash.union(By, With)
不是我要找的。
你可以用 reduce 做到这一点
const arrayToBeCompacted = [
{
section: "Section name 1",
path: ["segment1", "segment2"],
ids: ["id1"]
},
{
section: "Section name 1",
path: ["segment1", "segment2"],
ids: ["id2"]
},
{
section: "Section name2",
path: ["segment1", "segment2"],
ids: ["id3"]
},
{
section: "Another section",
path: ["segment1", "segment2"],
ids: ["id4"]
},
{
section: "Another section",
path: ["segment1", "segment2"],
ids: ["id5"]
},
]
const compacted = Object.values(arrayToBeCompacted.reduce((res, {section, path, ids}) => {
const key = section + path.join('|')
const existing = res[key] || {ids: [], section, path}
existing.ids = [...existing.ids, ...ids]
res[key] = existing
return res
}, {}))
console.log(compacted)
以下是实现目标的一种可能方法。
代码段
// method to compact array of objects
const compactArr = arr => (
Object.values( // extract values from intermediate result-obj
arr.reduce( // iterate over the array using "reduce"
(acc, itm) => { // "acc" is the accumuator/aggregator
const {section, ids, path} = itm; // de-structure to get props
// construct uniq-key using "section" and "path"
const uniqKey = `${section}-${path.join('-')}`;
acc[uniqKey] = {
...(acc[uniqKey] || {}),
section, path, // if "section" already exists, concat "ids"
ids: (acc[uniqKey]?.ids ?? []).concat(ids)
}
return acc;
},
{} // initial value of "acc" is empty-object {}
)
) // implicit return from method
);
const arrayToBeCompacted = [{
section: "Section name 1",
path: ["segment1", "segment2"],
ids: ["id1"]
},
{
section: "Section name 1",
path: ["segment1", "segment2"],
ids: ["id2"]
},
{
section: "Section name2",
path: ["segment1", "segment2"],
ids: ["id3"]
},
{
section: "Another section",
path: ["segment1", "segment2"],
ids: ["id4"]
},
{
section: "Another section",
path: ["segment1", "segment2"],
ids: ["id5"]
},
];
console.log('compacted array: ', compactArr(arrayToBeCompacted));
.as-console-wrapper { max-height: 100% !important; top: 0 }
说明
在上面的代码片段中添加了内联评论。