user14580333
user14580333

Reputation: 11

add elements to object - javascript

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

Answers (3)

pilchard
pilchard

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

Grant Herman
Grant Herman

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

Phil
Phil

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

Related Questions