Jim41Mavs
Jim41Mavs

Reputation: 572

How to combine array of objects into one object and then create another object within that array based on a condition on the index

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.

Upvotes: 1

Views: 104

Answers (4)

A1exandr Belan
A1exandr Belan

Reputation: 4780

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}

Upvotes: 0

ruleboy21
ruleboy21

Reputation: 6371

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)

Upvotes: 0

Bravo
Bravo

Reputation: 6264

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; }

Upvotes: 3

DecPK
DecPK

Reputation: 25406

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; }

Upvotes: 0

Related Questions