6

I ran into this problem, I was able to write solution which can handle array of object (not posted here) or one level deep nested object but i couldn't solve when the given object has nested structure like below. I am curious to know how we can solve this.

const source = {
  a: 1,
  b: {
    c: true,
    d: {
      e: 'foo'
    }
  },
  f: false,
  g: ['red', 'green', 'blue'],
  h: [{
    i: 2,
    j: 3
  }]
};

solution should be

const solution = {
    'a': 1,
    'b.c': true,
    'b.d.e': 'foo',
    'f': false,
    'g.0': 'red',
    'g.1': 'green',
    'g.2': 'blue',
    'h.0.i': 2,
    'h.0.j': 3
};

attempt for one deep nested object

let returnObj = {}

let nestetdObject = (source, parentKey) => {

    let keys = keyFunction(source);

    keys.forEach((key) => {
      let values = source[key];

      if( typeof values === 'object' && values !== null ) {
        parentKey = keys[0]+'.'+keyFunction(values)[0]
        nestetdObject(values, parentKey);
      }else{
        let key = parentKey.length > 0 ? parentKey : keys[0];
        returnObj[key] = values;
      }
    })
    return returnObj
};

// Key Extractor 
let keyFunction = (obj) =>{
  return Object.keys(obj);
}

calling the function

nestetdObject(source, '')

But my attempt will fail if the object is like { foo: { boo : { doo : 1 } } }.

4 Answers 4

23

You should be able to do it fairly simply with recursion. The way it works, is you just recursively call a parser on object children that prepend the correct key along the way down. For example (not tested very hard though):

const source = {
  a: 1,
  b: {
    c: true,
    d: {
      e: 'foo'
    }
  },
  f: false,
  g: ['red', 'green', 'blue'],
  h: [{
    i: 2,
    j: 3
  }]
}

const flatten = (obj, prefix = '', res = {}) => 
  Object.entries(obj).reduce((r, [key, val]) => {
    const k = `${prefix}${key}`
    if(typeof val === 'object'){ 
      flatten(val, `${k}.`, r)
    } else {
      res[k] = val
    }
    return r
  }, res)
 
console.log(flatten(source))

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

Comments

2

I am very late to the party but it can be easily achieved with a module like Flatify-obj.

Usage:

   const flattenObject = require('flatify-obj');

   flattenObject({foo: {bar: {unicorn: '🦄'}}})
   //=> { 'foo.bar.unicorn': '🦄' }

   flattenObject({foo: {unicorn: '🦄'}, bar: 'unicorn'}, {onlyLeaves: true});
   //=> {unicorn: '🦄', bar: 'unicorn'}

Comments

0

// Licensed under CC0

// To the extent possible under law, the author(s) have dedicated all copyright
// and related and neighboring rights to this software to the public domain
// worldwide. This software is distributed without any warranty.

const source = {
  a: 1,
  b: { c: true, d: { e: "foo" } },
  f: false,
  g: ["red", "green", "blue"],
  h: [{ i: 2, j: 3 }],
};

function flatten(source, parentKey, result = {}) {
  if (source?.constructor == Object || source?.constructor == Array) {
    for (const [key, value] of Object.entries(source)) {
      flatten(
        value,
        parentKey != undefined ? parentKey + "." + key : key,
        result
      );
    }
  } else {
    result[parentKey] = source;
  }

  return result;
}

console.log(flatten(source));

Comments

-1

one more simple example with Object.keys

 const apple = { foo: { boo : { doo : 1 } } }


let newObj = {}
const format = (obj,str) => {
  Object.keys(obj).forEach((item)=>{
     if(typeof obj[item] ==='object'){
        const s = !!str? str+'.'+item:item
        format(obj[item],s)
     } else {
       const m = !!str?`${str}.`:''
       newObj[m+item]= obj[item]
     }
  })

}

format(apple,'')

console.log(newObj)

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.