I'm attempting to join an array of objects with the "same" keys as one array. Basically the what I mean by "same keys" is that these keys will vary in only on number, in which doesn't matter. For example:
{ names.0.id: "Here" }
{ names.1.id: "Almost" }
{ names.2.id: "There" }
...
I wan't to join all the keys that have the following syntax into one. Like:
{ names: ["Here", "Almost", "There"] }
I have a array of arrays containing this data.
[{
"id": "123"
}, {
"group_name": "Test Group"
}, {
"admin": "Somthing"
}, {
"email_address": "[email protected]"
}, {
"org.id": "4"
}, {
"created_by": "6"
}, {
"updated_by": "6"
}, {
"students.0.id": "Yes"
}, {
"students.1.id": "No"
}, {
"names.0.id": "Here"
}, {
"names.1.id": "Almost"
}, {
"names.2.id": "There"
}],
[{
"id": "125"
}...
]
...
What I would like to accomplish:
[{
"id": "123"
}, {
"group_name": "Test Group"
}, {
"admin": "Somthing"
}, {
"email_address": "[email protected]"
}, {
"org.id": "4"
}, {
"created_by": "6"
}, {
"updated_by": "6"
}, {
"students": ["Yes", "No"]
}, {
"names": ["Here", "Almost", "There"]
}]
For any other keys that have this syntax of:
name.number.id
I would always like to join in a single array with the first part of the name
CodePudding user response:
I would suggest to split the problem in to three parts:
- Transform your arrays of
{ key: value }
objects in to single, nested objects - Flatten such nested objects to replace the
{ id: ... }
objects with just their values - Translate back to one-object per key-value-pair
1. Merging to a single object
To build up a nested object, we split each key by "."
. We then loop over the keys in pairs to create our nested layers. When a key is numeric, we add an array. See mergeKvp
in the snippet below.
2. Flattening to get rid of { id }
To flatten, we traverse the tree. Whenever we see an object that has only an id
property, we replace it by that object's id value. See flattenObj
in the snippet below.
//// UTILS
// Merge a key value pair in to an object splitting by "."
const mergeKvp = (obj, [key, value]) => {
const path = key.split(".");
let target = obj;
for (let i = 0; i < path.length - 1; i = 1) {
const k1 = path[i];
const k2 = path[i 1];
if (!target[k1]) target[k1] = isNaN( k2) ? {} : [];
target = target[k1];
}
target[path.at(-1)] = value;
return obj;
}
// Flatten a nested object structure
const flattenObj = obj => {
// Handle arrays
if (Array.isArray(obj)) return obj.map(flattenObj);
// Handle objects
if (Object(obj) === obj) {
// Replace { id: _ } objects with _
if ("id" in obj && Object.keys(obj).length === 1) return obj.id;
// Recurse for other objects
return Object.fromEntries(
Object.entries(obj).map(([k, v]) => [k, flattenObj(v)])
);
}
// Return value for everything else
return obj;
}
//// APP
// Merge KVP objects in to one big object
const base = Object.assign({}, ...getData());
// Create nested structures out of the dot-keys
const tree = Object.entries(base).reduce(mergeKvp, {})
// Flatten the tree
const output = flattenObj(tree);
// Translate back to array of { key: value } objects
console.log(
Object.entries(output).map(([k, v]) => ({ [k]: v }))
);
function getData() { return [{
"id": "123"
}, {
"group_name": "Test Group"
}, {
"admin": "Somthing"
}, {
"email_address": "[email protected]"
}, {
"org.id": "4"
}, {
"created_by": "6"
}, {
"updated_by": "6"
}, {
"students.0.id": "Yes"
}, {
"students.1.id": "No"
}, {
"names.0.id": "Here"
}, {
"names.1.id": "Almost"
}, {
"names.2.id": "There"
}]; };