Reputation: 11
I'm trying to build an object given an array of objects
const someArray = [
{
name: 'x.y',
value: 'Something for Y'
},
{
name: 'x.a.z',
value: 'Something for Z'
}
]
to look like this
{
x: {
a: {
z: 'Something for Z'
},
y: 'Something for Y'
}
}
I have this code
const buildObj = data => {
let obj = {}
data.forEach(item => {
let items = item.name.split('.')
items.reduce((acc, val, idx) => {
acc[val] = (idx === items.length - 1) ? item.value : {}
return acc[val]
}, obj)
})
return obj
}
buildObj(someArray)
but it doesn't include the y keypair. what's missing?
Upvotes: 1
Views: 180
Reputation: 12911
Here's an option using for loops and checking nesting from the top down.
const someArray = [
{
name: 'x.y',
value: 'Something for Y'
},
{
name: 'x.a.z',
value: 'Something for Z'
}
]
function parseArr(arr) {
const output = {};
for (let i = 0; i < arr.length; i++) {
const {name, value} = arr[i];
const keys = name.split('.');
let parent = output;
for (let j = 0; j < keys.length; j++) {
const key = keys[j];
if (!parent.hasOwnProperty(key)) {
parent[key] = j === keys.length - 1 ? value : {};
}
parent = parent[key];
}
}
return output;
}
console.log(parseArr(someArray));
Upvotes: 0
Reputation: 973
This is ABD at this point but I did it with a recursive builder of the path.
const someArray = [
{
name: 'x.y',
value: 'Something for Y'
},
{
name: 'x.a.z',
value: 'Something for Z'
}
]
const createPath = (path, value) => {
if(path.length === 1){
let obj = {}
obj[path.shift()] = value
return obj
}
let key = path.shift();
let outObject = {}
outObject[key] = { ...createPath(path, value) }
return outObject
}
const createObjectBasedOnDotNotation = (arr) => {
let outObject = {}
for(let objKey in arr){
const { name, value } = arr[objKey];
let object = createPath(name.split("."), value)
let mainKey = Object.keys(object)[0];
!outObject[mainKey] ?
outObject[mainKey] = {...object[mainKey]} :
outObject[mainKey] = {
...outObject[mainKey],
...object[mainKey]
}
}
return outObject
}
console.log(createObjectBasedOnDotNotation(someArray))
Upvotes: 0
Reputation: 164732
What you want to do is create an object, then for each dotted path, navigate through the object, creating new object properties as you go for missing parts, then assign the value to the inner-most property.
const someArray = [{"name":"x.y","value":"Something for Y"},{"name":"x.a.z","value":"Something for Z"}]
const t1 = performance.now()
const obj = someArray.reduce((o, { name, value }) => {
// create a path array
const path = name.split(".")
// extract the inner-most object property name
const prop = path.pop()
// find or create the inner-most object
const inner = path.reduce((i, segment) => {
// if the segment property doesn't exist or is not an object,
// create it
if (typeof i[segment] !== "object") {
i[segment] = {}
}
return i[segment]
}, o)
// assign the value
inner[prop] = value
return o
}, {})
const t2 = performance.now()
console.info(obj)
console.log(`Operation took ${t2 - t1}ms`)
.as-console-wrapper { max-height: 100% !important; }
Upvotes: 1