Home > Software engineering >  JavaScript - Merge Object Array Every nth Element
JavaScript - Merge Object Array Every nth Element

Time:11-04

I have an array of varying length containing objects in which each group of 4 corresponds to one element of interest (unfortunately this array cannot be changed)

Obviously there is a lot of duplicate data except for the description, correctiveAction etc.

[
 {
   ids: ['123', '124'],
   referenceNumbers: [],
   description: '',
 },
 {
   ids: ['123', '124'],
   referenceNumbers: [],
   correctiveAction: '',
 },
{
   ids: ['123', '124'],
   referenceNumbers: [],
   correctedBy: '',
 },
{
   ids: ['123', '124'],
   referenceNumbers: [],
   description: '',
   correctedDate:
 },
 ...

]

I am looking for a more elegant and efficient method of merging each group of 4 elements in this array, without duplicating the common fields.

This is my current solution, which works in the exact way I need it to, albeit inefficient:

const handleMergeDef = (defArr) => {
    let tempArr = []
    for (let i = 0; i < defArr.length; i  ) {
      tempArr.push({
        ids: defArr[i].ids,
        referenceNumbers: defArr[i].referenceNumbers,
        description: defArr[i].description,
        correctiveAction: defArr[i 1].correctiveAction,
        correctedBy: defArr[i 2].correctedBy,
        correctedDate: defArr[i 3].correctedDate
      })
      i =3
    }
    return tempArr
  }

Expected Output:

[
 {
   ids: ['123', '124'],
   referenceNumbers: [],
   description: '',
   correctiveAction: '',
   correctedBy: '',
   correctedDate: ''
 },
 {
   ids: ['456', '457'],
   referenceNumbers: [],
   description: '',
   correctiveAction: '',
   correctedBy: '',
   correctedDate: ''
 },
 ...
]

CodePudding user response:

You oculd iterate while iterating the wanted properties from the certain offsets.

const
    mergeBy = (data, properties) => {
        const result = [];
        let i = 0;

        while (i < data.length) {
            const o = {};
            for (const props of properties) {
                for (const p of [].concat(props)) o[p] = data[i][p];
                i  ;
            }
            result.push(o);
        } 

        return result;
    },
    data = [{ ids: ['123', '124'], referenceNumbers: [], description: '' }, { ids: ['123', '124'], referenceNumbers: [], correctiveAction: '' }, { ids: ['123', '124'], referenceNumbers: [], correctedBy: '' }, { ids: ['123', '124'], referenceNumbers: [], description: '', correctedDate: '' }],
    result = mergeBy(data, [
        ['ids', 'referenceNumbers', 'description'],
        'correctiveAction',
        'correctedBy',
        'correctedDate'
    ]);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

CodePudding user response:

Provided that the input reliably appears in sequential quartets, in principle, your solution is fine.

Depending on how much data you're dealing with, you could get some performance lift by predefining your output array length and assigning objects by explicit index, rather than pushing/resizing the array each time.

const reduce = (array) => {
  const n = array.length;
  const output = new Array(Math.ceil(n / 4));
  let i = 0;
  let x = 0;
  while (i < n) {
    output[x  ] = {
      ids: array[i].ids,
      referenceNumbers: array[i].referenceNumbers,
      description: array[i].description,
      correctiveAction: array[i   1].correctiveAction,
      correctedBy: array[i   2].correctedBy,
      correctedDate: array[i   3].correctedDate,
    }
    i  = 4;
  };
  return output;
};

const input = [
  {
    ids: ['123', '124'],
    referenceNumbers: [],
    description: '',
  },
  {
    ids: ['123', '124'],
    referenceNumbers: [],
    correctiveAction: 'Terminate',
  },
  {
    ids: ['123', '124'],
    referenceNumbers: [],
    correctedBy: 'Jane',
  },
  {
    ids: ['123', '124'],
    referenceNumbers: [],
    description: '',
    correctedDate: "2022-10-31"
  },
  {
    ids: ['456', '457'],
    referenceNumbers: [],
    description: '',
  },
  {
    ids: ['456', '457'],
    referenceNumbers: [],
    correctiveAction: 'Promote',
  },
  {
    ids: ['456', '457'],
    referenceNumbers: [],
    correctedBy: 'John',
  },
  {
    ids: ['456', '457'],
    referenceNumbers: [],
    description: '',
    correctedDate: "2022-11-01"
  },  
  {
    ids: ['678', '689'],
    referenceNumbers: [],
    description: '',
  },
  {
    ids: ['678', '689'],
    referenceNumbers: [],
    correctiveAction: 'Transfer',
  },
  {
    ids: ['678', '689'],
    referenceNumbers: [],
    correctedBy: 'Xander',
  },
  {
    ids: ['678', '689'],
    referenceNumbers: [],
    description: '',
    correctedDate: "2022-11-03"
  },   
];

const output = reduce(input);

console.log(output);

// minor translation for table display
console.table(output.map(o=>{
  o.ids = o.ids.join(",");
  o.referenceNumbers = o.referenceNumbers.join(",");
  return o;
}));
<script src="https://gh-canon.github.io/stack-snippet-console/console.min.js"></script><style>.as-console-wrapper{display:block}</style><script>console.config({timeStamps:false,maximize:true})</script>

  • Related