Tuesday 15 November 2022

Create dot notation array of strings from an Object

Last night, I created an object from an array of strings with dot notation; I needed to do that because I had previously flattened an object into those strings. I did this long and laboriously, but I asked a colleague to see if he could figure out how to do it using recursion. He did, and I'd like to share it here.

If we have this object:

{
  "thingOne": {
    "thingTwo": {
      "thingThree": true,
      "thingFour": true
    }
  },
  "thingyOne": {
    "thingyTwo": {
      "thingyThree": true,
      "thingyFour": true
    }
  }
}

Then this code:

(() => {

  const obj = {
    "thingOne": {
      "thingTwo": {
        "thingThree": true,
        "thingFour": true
      }
    },
    "thingyOne": {
      "thingyTwo": {
        "thingyThree": true,
        "thingyFour": true
      }
    }
  }

  const getObjStringsArr = (o = {}, arr = [], name = '') => {
    Object.keys(o).forEach(key => {
      if (o[key] === true) {
        arr.push(`${name}${key}`)
      } else {
        const nested = getObjStringsArr(o[key], arr, `${name}${key}.`)
        arr.concat(nested)
      }
    });
    return arr
  }

  console.log(getObjStringsArr(obj))

})()

It's brilliant having colleagues; it's even better having colleagues with huge brains! Thanks, Hamish!

It's not necessarily faster than my cludge, but it is far more elegant!

Monday 14 November 2022

Create an Object from dot notation

This was puzzling me all afternoon, and I came up with a bloody terrible work-around using eval, this evening I decided to do a little more research and found this answer on StackOverflow.

I've adapted it and it seems to work a treat:

(() => {

  const obj = {}

  const expand = (output, mystr, value) => {
    const items = mystr.split(".") // split on dot notation
    let ref = output // keep a reference of the new object
    //  loop through all nodes, except the last one
    for (let i = 0; i < items.length - 1; i++) {
      if (!ref[items[i]]) {
        // create a new element inside the reference
        ref[items[i]] = {}
      }
      ref = ref[items[i]] // shift the reference to the newly created object 
    }
    ref[items[items.length - 1]] = value // apply the final value
    return output // return the full object
  }

  const arr = [
    "thingOne.thingTwo.thingThree",
    "thingOne.thingTwo.thingFour",
    "thingyOne.thingyTwo.thingyThree",
    "thingyOne.thingyTwo.thingyFour"
  ]

  arr.forEach(a => {
    expand(obj, a, true)
  })
  
  console.log(obj)

})()

I was nearly there on my tod TBH, but wussed out at the end, thisis lovely though! It produces this lovely object:

{
  "thingOne": {
    "thingTwo": {
      "thingThree": true,
      "thingFour": true
    }
  },
  "thingyOne": {
    "thingyTwo": {
      "thingyThree": true,
      "thingyFour": true
    }
  }
}