1

I've been coding at this solution for hours now and can't seem to make much progress anymore. It's a very difficult function to write. Here is my input:

var testObj = {
  'b': 'num',
  'a': {
    'd': 'num',
    'c': 'num'
  },
  'g': ['num', 'num', {
    'x': 'num',
    'y': 'num'
  }],
  'e': 'num'
};

And here's the output I'm trying to generate from above:

var flatTestObj = [
  ['b', 'num'],
  ['a', 'obj'],
  ['a', 'obj', 'd', 'num'],
  ['a', 'obj', 'c', 'num'],
  ['g', 'arr'],
  ['g', 'arr', 0, 'num'],
  ['g', 'arr', 1, 'num'],
  ['g', 'arr', 2, 'obj'],
  ['g', 'arr', 2, 'obj', 'x', 'num'],
  ['g', 'arr', 2, 'obj', 'y', 'num'],
  ['e', 'num']
];

(Later I'm going to alphabetize the keys too but I can handle that part on my own so I excluded that from the question to make it easier to answer) but yeah the point is to guarantee the same order traversal of objects of this format later on.

Basically, have it recursively go through the object and add each key/index mapping as a new element to flatTestObj so later you can iterate through flatTestObj and get every member from testObj by referencing every other element from the current flatTestObj index array value.

Here's what I have so far but I'm having difficulty getting it to work with nesting:

var flattened = [];

function flatten(json, acc) {
  var keys = Object.keys(json);

  for (var i = 0; i < keys.length; i++) {
    var key = keys[i];
    var val = json[key];

    var strVal = typeof val === 'object' ? 'obj' : val;

    if (acc.length === 0) {
      acc = [key, strVal];
    } else {
      acc = acc.concat([key, strVal]);
    }

    if (typeof val === 'object') {
      flatten(val, acc);
    } else {
      flattened.push(acc);
      acc = [];
    }
  }
}

flatten(testObj, []);

2 Answers 2

1

This gives the output you're looking for:

var flattened = [];
function flatten(json, acc, inArray) {
  var key;

  acc = acc || [];
  for(key in json) {
    if(inArray) {
      key = +key;  //coerce to number
    }
    if(json[key] instanceof Array) {
      flattened.push(acc.concat([key, 'arr']));
      flatten(json[key], acc.concat([key, 'arr']), true);
    }
    else if(json[key] instanceof Object) {
      flattened.push(acc.concat([key, 'obj']));
      flatten(json[key], acc.concat([key, 'obj']));
    }
    else {
      flattened.push(acc.concat(key, json[key]));
    }
  }
} //flatten

Essentially, you need to include acc.concat() each time you push to the flattened array.

var testObj = {
  'b': 'num',
  'a': {
    'd': 'num',
    'c': 'num'
  },
  'g': ['num', 'num', {
    'x': 'num',
    'y': 'num'
  }],
  'e': 'num'
};

var flattened = [];
function flatten(json, acc, inArray) {
  var key;
  
  acc = acc || [];
  for(key in json) {
    if(inArray) {
      key = +key;  //coerce to number
    }
    if(json[key] instanceof Array) {
      flattened.push(acc.concat([key, 'arr']));
      flatten(json[key], acc.concat([key, 'arr']), true);
    }
    else if(json[key] instanceof Object) {
      flattened.push(acc.concat([key, 'obj']));
      flatten(json[key], acc.concat([key, 'obj']));
    }
    else {
      flattened.push(acc.concat(key, json[key]));
    }
  }
} //flatten

flatten(testObj);
console.log(JSON.stringify(flattened));

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

1 Comment

Beautiful! So simple too! Thank you so much! I'm going to study this for a while but it looks perfect! Except for array indicies being set as strings in the flattened array but I think I can figure out how to fix that.
1

Here's one way to do it with recursive function calls

var testObj = {
    'b': 'num',
    'a': {
        'd': 'num',
        'c': 'num'
    },
    'g': ['num', 'num', {
        'x': 'num',
        'y': 'num'
    }],
    'e': 'num'
};

var flatTestObj = (function it(what, arr, chain) {
    if (typeof what === "object") {
        var fn = function(k) {
            var type = Array.isArray(what[k]) ? 'arr' : 'obj' ,
            	vArr = [k, typeof what[k] === "object" ? type : what[k]],
                fArr = chain.concat(vArr);
                            
            arr.push(fArr); 
            it(what[k], arr, fArr);
        }

    	if (Array.isArray(what)) for (var i in what) fn(i)
        else Object.keys(what).forEach(fn);
    }
    return arr;
})(testObj, [], []);

document.body.innerHTML = '<pre>' + JSON.stringify(flatTestObj, 0, 4) + '</pre>';

1 Comment

Eeek, looks like someone answered while you were making this. Hopefully it can help out someone. I upvoted you anyway!

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.