Say I have the following JSON array:
[
{
"name": "x",
"category": "y",
"attributes": {
"name": "a",
"description": "b"
}
},
{
"name": "x",
"category": "y",
"attributes": {
"name": "c",
"description": "d"
}
}
]
How can I combine the elements where each property is identical, but add the differing properties to a nested array:
[
{
"name": "x",
"category": "y",
"attributes": [
{
"name": "a",
"description": "b"
},
{
"name": "c",
"description": "d"
}
]
}
]
To be more specific, any differing elements should be appended to the array— for example if the attribute with name "c" had description "b", I would still want the entire attribute appended to the "attributes" list.
I've been unable to find this problem on StackOverflow through extensive searching. I appreciate your help!
I was able to slightly modify my inputs to achieve a solution (I have limited knowledge of JS). The new inputs are:
const myJson = [{
"name": "x",
"category": "y",
"attributes": {
"name": "a",
"description": "b"
}
},
{
"attributes": {
"name": "c",
"description": "d"
}
},
{
"category": "z"
}
]
Now I can iterate through the items (in order). If an item lacks the "masterKey," (in this case "name"), I will add that key/value to the last item with the masterKey or create a list of values & append.
function mergeObjects_(objects) {
var result = [];
const masterKey = 'name';
for (let i = 0; i < objects.length; i++) {
let object = objects[i];
if (object.hasOwnProperty(masterKey)) {
result.push(object);
} else {
for (const [key, value] of Object.entries(object)) {
if (Array.isArray(result[result.length - 1][key])) {
result[result.length - 1][key].push(value);
} else {
var attribute_arr = [result[result.length - 1][key]];
attribute_arr.push(value);
result[result.length - 1][key] = attribute_arr;
}
}
}
}
return result;
}
This collapses the sample to the following and works across multiple items
[
{
"name": "x",
"category": [
"y",
"z"
],
"attributes": [
{
"name": "a",
"description": "b"
},
{
"name": "c",
"description": "d"
}
]
}
]
Of course, this assumes one of the trailing properties exists in the object with the masterKey. For my purposes, this is OK given how the data is generated. Thank you all for your answers and help!
The most straightforward way is to use the reduce function
const data = [
{
name: 'x',
category: 'y',
attributes: {
name: 'a',
description: 'b',
},
},
{
name: 'x',
category: 'y',
attributes: {
name: 'c',
description: 'd',
},
},
];
const answer = data.reduce((result, current) => {
const findIndex = result.findIndex((item) => item.name === current.name);
// if the name does not exist in the result, append it to the result array
if (findIndex === -1) {
return [
...result,
{
name: current.name,
category: current.category,
attributes: [current.attributes],
},
];
}
return result.map((value, index) => {
if (index === findIndex) {
value.attributes.push(current.attributes);
}
return value;
});
}, []);
console.log(answer);
//It's very simple and best for huge data
var arr = [
{
"name": "x",
"category": "y",
"attributes": {
"name": "a",
"description": "b"
}
},
{
"name": "x",
"category": "y",
"attributes": {
"name": "c",
"description": "d"
}
}
];
var newArr = [];
var objKeyValue = {};
arr.forEach(rec => {
if (objKeyValue[rec.name + rec.category])
objKeyValue[rec.name + rec.category].attributes.push(rec.attributes);
else objKeyValue[rec.name + rec.category] = { name: rec.name, category: rec.category, attributes: [rec.attributes] };
});
console.log("Output", Object.values(objKeyValue));