有条件地合并对象数组

Conditionally merge array of objects

我正在寻找一种优雅的方式(最好是不可变的,lodash - 好的)来有条件地压缩数组。 我想检查 sectionpath 值组合的重复项,并附加这些重复项的 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 }

说明

在上面的代码片段中添加了内联评论。