Chron Bag Chron Bag - 4 months ago 30
Javascript Question

How to convert a nested JavaScript object to a flat array?

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, []);

Answer

This gives the output you're looking for:

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

  acc = acc || [];
  for(key in json) {
    if(json[key] instanceof Array) {
      flattened.push(acc.concat([key, 'arr']));
      flatten(json[key], acc.concat([key, 'arr']));
    }
    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) {
  var key;
  
  acc = acc || [];
  for(key in json) {
    if(json[key] instanceof Array) {
      flattened.push(acc.concat([key, 'arr']));
      flatten(json[key], acc.concat([key, 'arr']));
    }
    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));

Comments