0

I have an array of objects with the same keys, I want to create a new array of objects that creates a new object that combines the uniques ones together into one


const arrayOfObjects = [
{ 'Serial Number': '90946117350061093222581604839920' },
{ 'Serial Number': '77362117350061093222581604891733' },
{ 'Serial Number': '77362117350061093222581604891734' },
{ 'Part Number': 'TR40-60C779-AA' },
{ 'Part Number': 'ST41-60C780-AA' },
{ 'Part Number': 'QT41-60C780-AA' },
{ 'Cell Count': '28' },
{ 'Cell Count': '27' },
{ 'Cell Count': '29' },
{ 'Length': '10' },
{ 'Length': '11' },
{ 'Length': '11' },
]

So it needs to look like the below.

const desiredArrayOfObjects = [
{ 
    'Serial Number': '90946117350061093222581604839920',
    'Part Number': 'TR40-60C779-AA',
    'Cell Count': '27',
    'Length': '10',
},
{ 
    'Serial Number': '77362117350061093222581604891733',
    'Part Number': 'ST41-60C780-AA',
    'Cell Count': '28',
    'Length': '11',
},
{ 
    'Serial Number': '77362117350061093222581604891734',
    'Part Number': 'QT41-60C780-AA',
    'Cell Count': '29',
    'Length': '12',
},

]

I have tried it with the code below, but i'm clearly not getting it right, help is welcome and appreciated.

let newArr = [];
arrayOfObjects.map((x,i) => {
    Object.entries(x).map(([key, value]) => {
        if(!newArr.length){
            
            if(Object.keys(newArr[i]).toString() === key){
                newArr.push({[key]: value})                   
            }

        }
    })
})
Jim41Mavs
  • 482
  • 4
  • 21
  • From my point of view, it's impossible to build up the `desiredArrayOfObjects` from `arrayOfObjects` because there is not any relationship among the objects in `arrayOfObjects`. I mean, I cannot see how to interrelate these objects. – Ele Apr 05 '22 at 16:11
  • @Ele I think it's based on the order. First Serial Number, first Part Number, first Cell Count, and first Length all go together. – mykaf Apr 05 '22 at 16:13
  • `if(!newArr.length){if(Object.keys(newArr[i]).toString() === key){` `newArr` doesn't have any entries, so how would you expect to set `newArr[i]` to a string? – mykaf Apr 05 '22 at 16:16
  • @user1599011 no, that's not true. See the `Length` `=` `12` – Ele Apr 05 '22 at 16:18
  • @Ele, how, when we just checked `if(!newArr.length){`? This is not the key `Length`, it's an array length. – mykaf Apr 05 '22 at 16:21
  • @user1599011 I'm talking about the `desiredArrayOfObjects` array (output). – Ele Apr 05 '22 at 16:24
  • 1
    @ele, I see. I think that's probably a typo. But definitely makes it difficult to understand. – mykaf Apr 05 '22 at 16:35

2 Answers2

2

I think it'best if you first separate them and the put it back together

const arrayOfObjects = [
{ 'Serial Number': '90946117350061093222581604839920' },
{ 'Serial Number': '77362117350061093222581604891733' },
{ 'Serial Number': '77362117350061093222581604891734' },
{ 'Part Number': 'TR40-60C779-AA' },
{ 'Part Number': 'ST41-60C780-AA' },
{ 'Part Number': 'QT41-60C780-AA' },
{ 'Cell Count': '28' },
{ 'Cell Count': '27' },
{ 'Cell Count': '29' },
{ 'Length': '10' },
{ 'Length': '11' },
{ 'Length': '11' },
]

const keys = ['Serial Number', 'Part Number', 'Cell Count', 'Length']

const separated = arrayOfObjects.reduce((res, item) => {
  const key = Object.keys(item)[0]
  const existing = res[key] || []
  res[key] = [...existing, item[key]]
  return res
}, {})

const result = separated[keys[0]].map((_, i) => {
  return keys.reduce((res, k ) => {
    return {...res, [k]: separated[k][i]}
  }, {})
})

console.log(result)
R4ncid
  • 6,944
  • 1
  • 4
  • 18
1

A solution that doesn't require knowing the properties ahead of time would be to separate the array into sub-arrays of matching property, and then map over the longest of these sub-arrays merging the contained objects into one. (This does require that all like properties be sequential in the source array.)

const arrayOfObjects = [{ 'Serial Number': '90946117350061093222581604839920' }, { 'Serial Number': '77362117350061093222581604891733' }, { 'Serial Number': '77362117350061093222581604891734' }, { 'Part Number': 'TR40-60C779-AA' }, { 'Part Number': 'ST41-60C780-AA' }, { 'Part Number': 'QT41-60C780-AA' }, { 'Cell Count': '28' }, { 'Cell Count': '27' }, { 'Cell Count': '29' }, { 'Length': '10' }, { 'Length': '11' }, { 'Length': '11' },];

const grouped = [];
let prev;
for (const obj of arrayOfObjects) {
  const [key] = Object.keys(obj);
  if (key !== prev) {
    grouped.push([]);
  }
  grouped.at(-1).push(obj);
  prev = key;
}

const result = grouped
  .sort(({ length: a }, { length: b }) => b - a)[0]
  .map((_, i) => Object.assign(...grouped.map(p => p[i] ?? {})));

console.log(result)

Or, using grouping if the order of the source array is unknown (the object the individual properties end up in will still be sensitive to the ordering of the source array)

const arrayOfObjects = [{ 'Serial Number': '90946117350061093222581604839920' }, { 'Serial Number': '77362117350061093222581604891733' }, { 'Serial Number': '77362117350061093222581604891734' }, { 'Part Number': 'TR40-60C779-AA' }, { 'Part Number': 'ST41-60C780-AA' }, { 'Part Number': 'QT41-60C780-AA' }, { 'Cell Count': '28' }, { 'Cell Count': '27' }, { 'Cell Count': '29' }, { 'Length': '10' }, { 'Length': '11' }, { 'Length': '11' },];

const grouped = {}
for (const obj of arrayOfObjects) {
  const [[key, value]] = Object.entries(obj);
  (grouped[key] ??= []).push(value);
}

const result = [];
for (const [key, values] of Object.entries(grouped)) {
  for (const [i, value] of values.entries()) {
    (result[i] ??= {})[key] = value;
  }
}

console.log(result)
pilchard
  • 12,414
  • 5
  • 11
  • 23
  • can you please explain the variable name "chunked"? The technical jargon/reasoning – Jim41Mavs Apr 05 '22 at 16:43
  • chunking is usually done by count ie to split a 1d array into a 2d array of equally sized sub-arrays [example](https://stackoverflow.com/questions/8495687/split-array-into-chunks), so it's not totally accurate to this use case. Should probably be 'grouped' which is a little more descriptive. – pilchard Apr 05 '22 at 16:45