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

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.