Home > Back-end >  concatenate nested array property of an object
concatenate nested array property of an object

Time:04-14

I have a JSONLines file containing thousands of items and I need to merge all of them but for arrays instead of merge need to concatenate them. I don't have the item schema so need to dynamically do this.

{title: 'test', data: [1]}
{title: 'test', data: [2]}
{title: 'test1', data: [3]}

and output will be something like this

{title: 'test1', data: [1,2,3]}

not sure what is the best performing way I can do.

CodePudding user response:

No so complicated You can separate the steps. Like:

const array = [
  { title: 'test', data: [1], data2: ['data1', 'data2'] },
  { title: 'test', data: [2], data2: [1, 2] },
  { title: 'test1', data: [3], data2: [1, 2, 3] },
  { title: 'test1', data2: [1, 2, 3] },
  { title: 'test1', data2: 'string' },
  { title: 'test3', data2: 69 },
];

const mergeAllKeys = (newArr, val, ix, mergeOn) => {
  return Object.keys(newArr[ix])
    .filter((k) => k !== mergeOn)
    .reduce((obj, k) => ({
      ...obj,
      [k]: [
        ...newArr[ix][k],
        ...(Array.isArray(val[k]) ? val[k] : [val[k]]),
      ].filter((v) => v),
    }), {});
};

const keysToArray = (val, mergeOn) => {
  return Object.keys(val)
    .filter((k) => k !== mergeOn)
    .reduce((o, k) => ({ ...o, [k]: Array.isArray(val[k]) ? val[k] : [val[k]] }), {});
};


function mergeBy(arr, mergeOn) {
  const memo = [];
  return arr.reduce((newArr, val) => {
    const ix = memo.findIndex((v) => v === val[mergeOn]);
    if (ix > -1) {
      newArr[ix] = {
        [mergeOn]: newArr[ix][mergeOn],
        ...mergeAllKeys(newArr, val, ix, mergeOn),
      };
      return newArr;
    }
    memo.push(val[mergeOn]);
    return [
      ...newArr,
      {
        [mergeOn]: val[mergeOn],
        ...keysToArray(val, mergeOn),
      },
    ];
  }, []);



And later put it all together:

const array = [
  { title: 'test', data: [1], data2: ['data1', 'data2'] },
  { title: 'test', data: [2], data2: [1, 2] },
  { title: 'test1', data: [3], data2: [1, 2, 3] },
  { title: 'test1', data2: [1, 2, 3] },
  { title: 'test1', data2: 'string' },
  { title: 'test3', data2: 69 },
];

function mergeBy(arr, mergeOn) {
  const memo = [];
  return arr.reduce((newArr, val) => {
    const ix = memo.findIndex((v) => v === val[mergeOn]);
    if (ix > -1) {
      newArr[ix] = {
        [mergeOn]: newArr[ix][mergeOn],
        ...Object.keys(newArr[ix])
          .filter((k) => k !== mergeOn)
          .reduce((obj, k) => ({
            ...obj,
            [k]: [
              ...newArr[ix][k],
              ...(Array.isArray(val[k]) ? val[k] : [val[k]]),
            ].filter((v) => v),
          }), {}),
      };
      return newArr;
    }
    memo.push(val[mergeOn]);
    return [
      ...newArr,
      {
        [mergeOn]: val[mergeOn],
        ...Object.keys(val)
          .filter((k) => k !== mergeOn)
          .reduce((o, k) => ({ ...o, [k]: Array.isArray(val[k]) ? val[k] : [val[k]] }), {}),
      },
    ];
  }, []);
}

const funkyMerge = mergeBy(array, 'title');
console.log('funkyMerge: ', funkyMerge);

  • Related