1

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?

11
  • SO can you walk me through what that conversion is? you check name and then create an object structure based on that? then if a key already exists you just update that key with a the new value and you create this structure based on the a.b.c structure so a.b.c => { a: { b: { c{} } } Commented Nov 4, 2020 at 23:50
  • yea pretty much Commented Nov 4, 2020 at 23:52
  • Okay cool and any value is fair game, correct? Commented Nov 4, 2020 at 23:53
  • See Create an object out of dot notation. Other than that, why not step through the code with a debugger? Commented Nov 4, 2020 at 23:53
  • 1
    acc[val] = (idx === items.length - 1) ? item.value : {} overwrites the previous x property with another empty object. Look into Object.assign or spread. Commented Nov 5, 2020 at 0:00

3 Answers 3

1

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; }

Sign up to request clarification or add additional context in comments.

Comments

0

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))

Comments

0

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));

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.