Home > Back-end >  How to combine array of objects into one object and then create another object within that array bas
How to combine array of objects into one object and then create another object within that array bas

Time:03-16

I have an array of objects that i need to flatten/simplify/combine based on certain conditions. Here is the shape of my current array of objects below:

const arrayOfObjects = 
  [ { Battery           : 'Battery'        } 
  , { batteryDetailsKey : [ 'Serial Number', 'Type', 'Part Number'       ] } 
  , { batteryDetailsVal : [ 'HJ3CA19347410218LJ98 100 QC', 'Extended Range', '4P94-Q001' ] } 
  , { Modules           : 'Modules'        } 
  , { moduleDetailsKey  : [ 'Serial Number', 'Part Number', 'Cell Count' ] } 
  , { moduleDetailsVal  : [ '83675327350061093222581609899001', 'LJ98-10C779-A01', '32'  ] } 
  , { assetSeparator    : 'assetSeparator' } 
  , { Battery           : 'Battery'        }  
  , { batteryDetailsKey : [ 'Serial Number', 'Type', 'Part Number'       ] } 
  , { batteryDetailsVal : [ 'HJ3CA19347410218LJ98 101 QC', 'Extended Range', '4P94-Q002' ] } 
  , { Modules           : 'Modules'        } 
  , { moduleDetailsKey  : [ 'Serial Number', 'Part Number', 'Cell Count' ] } 
  , { moduleDetailsVal  : [ '83675327350061093222581609899002', 'LJ98-10C779-A02', '28'  ] } 
  , { moduleDetailsVal  : [ '83675327350061093222581609899003', 'LJ98-10C779-A03', '27'  ] } 
  , { assetSeparator    : 'assetSeparator' } 
  , { Battery           : 'Battery'        } 
  , { batteryDetailsKey : [ 'Serial Number', 'Type', 'Part Number'                       ] } 
  , { batteryDetailsVal : [ 'HJ3CA19347410218LJ98 102 QC', 'Extended Range', '4P94-Q003' ] } 
  , { Modules           : 'Modules'        } 
  , { moduleDetailsKey  : [ 'Serial Number', 'Part Number', 'Cell Count' ] } 
  , { moduleDetailsVal  : [ '83675327350061093222581609899004', 'LJ98-10C779-A01', '32'  ] } 
  ] ]

I basically want this arrayOfObjects to be shaped into this structure:

const shapeIWantArrayOfObjects = 
  [ { Battery           : 'Battery'
    , batteryDetailsKey : [ 'Serial Number', 'Type', 'Part Number' ] 
    , batteryDetailsVal : [ 'HJ3CA19347410218LJ98 100 QC', 'Extended Range', '4P94-Q001' ] 
    , Modules           : 'Modules'
    , moduleDetailsKey  : [ 'Serial Number', 'Part Number', 'Cell Count' ] 
    , moduleDetailsVal  : [ '83675327350061093222581609899001', 'LJ98-10C779-A01', '32' ] 
    } 
  , { Battery           : 'Battery'
    , batteryDetailsKey : [ 'Serial Number', 'Type', 'Part Number' ] 
    , batteryDetailsVal : [ 'HJ3CA19347410218LJ98 101 QC', 'Extended Range', '4P94-Q002' ] 
    , Modules           : 'Modules'
    , moduleDetailsKey  : [ 'Serial Number', 'Part Number', 'Cell Count'] 
    , moduleDetailsVal  : [ '83675327350061093222581609899002', 'LJ98-10C779-A02', '28' ] 
    , moduleDetailsVal  : [ '83675327350061093222581609899003', 'LJ98-10C779-A03', '27' ] 
    } 
  , { Battery           : 'Battery'
    , batteryDetailsKey : [ 'Serial Number', 'Type', 'Part Number' ] 
    , batteryDetailsVal : [ 'HJ3CA19347410218LJ98 102 QC', 'Extended Range', '4P94-Q003' ] 
    , Modules           : 'Modules'
    , moduleDetailsKey  : [ 'Serial Number', 'Part Number', 'Cell Count'] 
    , moduleDetailsVal  : [ '83675327350061093222581609899004', 'LJ98-10C779-A01', '32' ] 
    } 
  ] 

As you can see i'm basically wanting to combine the modules and batteries details into one object, then as you can see i want to create another object within that array once i hit the {"assetSeparator": "assetSeparator"}. That's like my conditional that tells me that asset has been combined, now time to combine the next one, almost think of it as string.split("assetSeparator")

Can someone please tell me how i could achieve this, i've tried Object.assign({}, ...arrayOfObjects) but that didn't quite achieve what i want, and i can't detect the {"assetSeparator": "assetSeparator"} using the spread operator.

I've also tried doing a reduce arrayOfObjects.reduce(function(result, current) { return Object.assign(result, current); }, {}) but because it's accumulating an object, it's just override object properties with the same keys. Please help.

CodePudding user response:

Please note, that your required output is IMPOSSIBLE - but if there's more than one object with the same key, the output could have an array of values for that key - see code

If each group of items in the original array begins with an object with a single key "Battery" - then this will perform the majicks for you

const arrayOfObjects = [{"Battery": "Battery"},{"batteryDetailsKey": ["Serial Number","Type","Part Number",]},{"batteryDetailsVal": ["HJ3CA19347410218LJ98 100 QC","Extended Range","4P94-Q001",]},{"Modules": "Modules"},{"moduleDetailsKey": ["Serial Number","Part Number","Cell Count",]},{"moduleDetailsVal": ["83675327350061093222581609899001","LJ98-10C779-A01","32",]},{"assetSeparator": "assetSeparator"},{"Battery": "Battery"},{"batteryDetailsKey": ["Serial Number","Type","Part Number"]},{"batteryDetailsVal": ["HJ3CA19347410218LJ98 101 QC","Extended Range","4P94-Q002"]},{"Modules": "Modules"},{"moduleDetailsKey": ["Serial Number","Part Number","Cell Count"]},{"moduleDetailsVal": ["83675327350061093222581609899002","LJ98-10C779-A02","28"]},{"moduleDetailsVal": ["83675327350061093222581609899003","LJ98-10C779-A03","27"]},{"assetSeparator": "assetSeparator"},{"Battery": "Battery"},{"batteryDetailsKey": ["Serial Number","Type","Part Number",]},{"batteryDetailsVal": ["HJ3CA19347410218LJ98 102 QC","Extended Range","4P94-Q003",]},{"Modules": "Modules"},{"moduleDetailsKey": ["Serial Number","Part Number","Cell Count",]},{"moduleDetailsVal": ["83675327350061093222581609899004","LJ98-10C779-A01","32",]}];

const shapeIWantArrayOfObjects = [];
let currentOutput;
for (let object of arrayOfObjects) {
    if (Object.keys(object).join('') === 'Battery') {
        currentOutput = {};
        shapeIWantArrayOfObjects.push(currentOutput);
    }
    Object.entries(object).forEach(([key, val]) => {
        const existing = currentOutput[key];
        if (!existing) {
            currentOutput[key] = val;
        } else {
            if (!Array.isArray(currentOutput[key][0])) {
                currentOutput[key] = [currentOutput[key]];
            }
            currentOutput[key].push(val);
        }
    });
}
console.log(shapeIWantArrayOfObjects);
.as-console-wrapper {max-height: 100%!important; top:0; }
.as-console-row::after { display:none !important; }

CodePudding user response:

You can group them based on the key of an object i.e. assetSeparator

const result = arrayOfObjects.reduce((acc, curr) => {
  if (new Set(Object.keys(curr)).has('assetSeparator')) {
    acc.push({});
  } else {
    if (!acc.length) acc.push({ ...curr });
    else {
      const last = acc[acc.length - 1];
      Object.keys(curr).forEach((k) => {
        last[k] = curr[k];
      });
    }
  }
  return acc;
}, []);

const arrayOfObjects = [
  {
    Battery: 'Battery',
  },
  {
    batteryDetailsKey: ['Serial Number', 'Type', 'Part Number'],
  },
  {
    batteryDetailsVal: [
      'HJ3CA19347410218LJ98 100 QC',
      'Extended Range',
      '4P94-Q001',
    ],
  },
  {
    Modules: 'Modules',
  },
  {
    moduleDetailsKey: ['Serial Number', 'Part Number', 'Cell Count'],
  },
  {
    moduleDetailsVal: [
      '83675327350061093222581609899001',
      'LJ98-10C779-A01',
      '32',
    ],
  },
  {
    assetSeparator: 'assetSeparator',
  },

  {
    Battery: 'Battery',
  },
  {
    batteryDetailsKey: ['Serial Number', 'Type', 'Part Number'],
  },
  {
    batteryDetailsVal: [
      'HJ3CA19347410218LJ98 101 QC',
      'Extended Range',
      '4P94-Q002',
    ],
  },
  {
    Modules: 'Modules',
  },
  {
    moduleDetailsKey: ['Serial Number', 'Part Number', 'Cell Count'],
  },
  {
    moduleDetailsVal: [
      '83675327350061093222581609899002',
      'LJ98-10C779-A02',
      '28',
    ],
  },
  {
    moduleDetailsVal: [
      '83675327350061093222581609899003',
      'LJ98-10C779-A03',
      '27',
    ],
  },
  {
    assetSeparator: 'assetSeparator',
  },
  {
    Battery: 'Battery',
  },
  {
    batteryDetailsKey: ['Serial Number', 'Type', 'Part Number'],
  },
  {
    batteryDetailsVal: [
      'HJ3CA19347410218LJ98 102 QC',
      'Extended Range',
      '4P94-Q003',
    ],
  },
  {
    Modules: 'Modules',
  },
  {
    moduleDetailsKey: ['Serial Number', 'Part Number', 'Cell Count'],
  },
  {
    moduleDetailsVal: [
      '83675327350061093222581609899004',
      'LJ98-10C779-A01',
      '32',
    ],
  },
];

const result = arrayOfObjects.reduce((acc, curr) => {
  if (new Set(Object.keys(curr)).has('assetSeparator')) {
    acc.push({});
  } else {
    if (!acc.length) acc.push({ ...curr });
    else {
      const last = acc[acc.length - 1];
      Object.keys(curr).forEach((k) => {
        last[k] = curr[k];
      });
    }
  }
  return acc;
}, []);

console.log(result);
/* This is not a part of answer. It is just to give the output full height. So IGNORE IT */
.as-console-wrapper { max-height: 100% !important; top: 0; }

CodePudding user response:

You can try something like this

const arrayOfObjects = [{"Battery": "Battery"}, {"batteryDetailsKey": ["Serial Number", "Type", "Part Number", ] }, {"batteryDetailsVal": ["HJ3CA19347410218LJ98 100 QC", "Extended Range", "4P94-Q001", ] }, {"Modules": "Modules"}, {"moduleDetailsKey": ["Serial Number", "Part Number", "Cell Count", ] }, {"moduleDetailsVal": ["83675327350061093222581609899001", "LJ98-10C779-A01", "32", ] }, {"assetSeparator": "assetSeparator"}, {"Battery": "Battery"}, {"batteryDetailsKey": ["Serial Number", "Type", "Part Number"] }, {"batteryDetailsVal": ["HJ3CA19347410218LJ98 101 QC", "Extended Range", "4P94-Q002"] }, {"Modules": "Modules"}, {"moduleDetailsKey": ["Serial Number", "Part Number", "Cell Count"] }, {"moduleDetailsVal": ["83675327350061093222581609899002", "LJ98-10C779-A02", "28"] }, {"moduleDetailsVal": ["83675327350061093222581609899003", "LJ98-10C779-A03", "27"] }, {"assetSeparator": "assetSeparator"}, {"Battery": "Battery"}, {"batteryDetailsKey": ["Serial Number", "Type", "Part Number", ] }, {"batteryDetailsVal": ["HJ3CA19347410218LJ98 102 QC", "Extended Range", "4P94-Q003", ] }, {"Modules": "Modules"}, {"moduleDetailsKey": ["Serial Number", "Part Number", "Cell Count", ] }, {"moduleDetailsVal": ["83675327350061093222581609899004", "LJ98-10C779-A01", "32", ] }];

let shapeIWantArrayOfObjects = [], tempObj = {}, i = 0;
arrayOfObjects.forEach(obj => {
    if( !obj.hasOwnProperty('assetSeparator') ){
        shapeIWantArrayOfObjects[i] = { ...shapeIWantArrayOfObjects[i], ...obj };
    }else{
        i  ;
        tempObj = {};
    }
});

console.log(shapeIWantArrayOfObjects)

CodePudding user response:

Another one solution. You can use hash grouping approach to combine objects by condition.

const arrayOfObjects = [{"Battery":"Battery"},{"batteryDetailsKey":["Serial Number","Type","Part Number"]},{"batteryDetailsVal":["HJ3CA19347410218LJ98 100 QC","Extended Range","4P94-Q001"]},{"Modules":"Modules"},{"moduleDetailsKey":["Serial Number","Part Number","Cell Count"]},{"moduleDetailsVal":["83675327350061093222581609899001","LJ98-10C779-A01","32"]},{"assetSeparator":"assetSeparator"},{"Battery":"Battery"},{"batteryDetailsKey":["Serial Number","Type","Part Number"]},{"batteryDetailsVal":["HJ3CA19347410218LJ98 101 QC","Extended Range","4P94-Q002"]},{"Modules":"Modules"},{"moduleDetailsKey":["Serial Number","Part Number","Cell Count"]},{"moduleDetailsVal":["83675327350061093222581609899002","LJ98-10C779-A02","28"]},{"moduleDetailsVal":["83675327350061093222581609899003","LJ98-10C779-A03","27"]},{"assetSeparator":"assetSeparator"},{"Battery":"Battery"},{"batteryDetailsKey":["Serial Number","Type","Part Number"]},{"batteryDetailsVal":["HJ3CA19347410218LJ98 102 QC","Extended Range","4P94-Q003"]},{"Modules":"Modules"},{"moduleDetailsKey":["Serial Number","Part Number","Cell Count"]},{"moduleDetailsVal":["83675327350061093222581609899004","LJ98-10C779-A01","32"]}];

let objectCount = 0;
const shapeIWantArrayOfObjects = Object.values(arrayOfObjects.reduce((acc, item) => {
  if (item.assetSeparator === "assetSeparator") {
    objectCount  = 1;
    return acc;
  }
  acc[objectCount] ??= {};
  acc[objectCount] = { ...acc[objectCount], ...item };
  
  return acc;
}, {}));

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

  • Related