I have written this small function to get all keys and values of an object and store them into an array. The object might contain arrays as values...
Object {
This solution can handle deeply nested objects
const isObject = o => o && typeof o === 'object' && !(o instanceof Date);
const flattenObject = obj => Object.entries(obj).reduce((acc, [key, val]) => ({
...acc, ...(isObject(val) ? flattenObject(val) : { [key]: val })
}), {});
Remember that this function returns an empty object for strings, dates, numbers, etc.
Generate an array of tuples (two-element arrays) of keys and values (which might themselves be arrays), then deep-flatten it.
function flattenObject(obj) {
return flatten(Object.keys(obj).map(k => [toNumber(k), obj[k]]));
}
// Substitute your own favorite flattening algorithm.
const flatten = a => Array.isArray(a) ? [].concat(...a.map(flatten)) : a;
// Convert to number, if you can.
const toNumber = n => isNaN(+n) ? n : +n;
console.log(flattenObject({a: [1, 2], b: 3, 0: [1, 2, 3, 4, 5]}));
Flattening Object can be done using recursion as below :
Sample Input
let obj = {
name: "test",
address: {
personal: "abc",
office: {
building : 'random'
street : 'some street',
}
}
}
Expected Output
{
name : "test",
address_personal: "abc"
address_office_building: "random"
address_office_street: "some street"
}
My Solution
function flattenObj(obj, parent, res = {}){
for(let key in obj){
let propName = parent ? parent + '_' + key : key;
if(typeof obj[key] == 'object'){
flattenObj(obj[key], propName, res);
} else {
res[propName] = obj[key];
}
}
return res;
}
Hope it helps
I wanted to flatten my deep object to one level depth. None of the above solutions worked for me.
My input:
{
"user": {
"key_value_map": {
"CreatedDate": "123424",
"Department": {
"Name": "XYZ"
}
}
}
}
Expected output:
{
"user.key_value_map.CreatedDate": "123424",
"user.key_value_map.Department.Name": "XYZ"
}
Code that worked for me:
function flattenObject(ob) {
var toReturn = {};
for (var i in ob) {
if (!ob.hasOwnProperty(i)) continue;
if ((typeof ob[i]) == 'object' && ob[i] !== null) {
var flatObject = flattenObject(ob[i]);
for (var x in flatObject) {
if (!flatObject.hasOwnProperty(x)) continue;
toReturn[i + '.' + x] = flatObject[x];
}
} else {
toReturn[i] = ob[i];
}
}
return toReturn;
}
This answer is an improvement of @Muthukrishnan 's answer
If you want to flatten an object deeply outputting the values into a one level deep object keyed with the path of the value in the previous object
(eg: { foo: { bar: 'baz'} }
=> { 'foo.bar': 'baz' }
)
Here is how you can effectively do it:
/**
* @param ob Object The object to flatten
* @param prefix String (Optional) The prefix to add before each key, also used for recursion
**/
function flattenObject(ob, prefix = false, result = null) {
result = result || {};
// Preserve empty objects and arrays, they are lost otherwise
if (typeof ob === 'object' && ob !== null && Object.keys(ob).length === 0) {
result[prefix] = Array.isArray(ob) ? [] : {};
return result;
}
prefix = prefix ? prefix + '.' : '';
for (const i in ob) {
if (Object.prototype.hasOwnProperty.call(ob, i)) {
if (typeof ob[i] === 'object' && ob[i] !== null) {
// Recursion on deeper objects
flattenObject(ob[i], prefix + i, result);
} else {
result[prefix + i] = ob[i];
}
}
}
return result;
}
/**
* Bonus function to unflatten an object
*
* @param ob Object The object to unflatten
*/
function unflattenObject(ob) {
const result = {};
for (const i in ob) {
if (Object.prototype.hasOwnProperty.call(ob, i)) {
const keys = i.match(/^\.+[^.]*|[^.]*\.+$|(?:\.{2,}|[^.])+(?:\.+$)?/g); // Just a complicated regex to only match a single dot in the middle of the string
keys.reduce((r, e, j) => {
return r[e] || (r[e] = isNaN(Number(keys[j + 1])) ? (keys.length - 1 === j ? ob[i] : {}) : []);
}, result);
}
}
return result;
}
// TESTS
const obj = {
value: {
foo: {
bar: 'yes',
so: {
freakin: {
nested: 'Wow',
}
}
},
},
// Some edge cases to test
test: [true, false, [null, undefined, 1]],
not_lost: [], // Empty arrays should be preserved
not_lost2: {}, // Empty objects should be preserved
// Be careful with object having dots in the keys
'I.like.dots..in.object.keys...': "... Please don't override me",
I: {
like: {
'dots..in': {
object: {
'keys...': "You've been overwritten"
}
}
}
}
};
console.log(flattenObject(['I', {'am': 'an array'}]));
let flat = flattenObject(obj);
console.log(flat, unflattenObject(flat));
There is an obvious problem that you could encounter with flattening this way if your object contains keys with dots, this is documented in the fiddle
You could just concat all keys and values. (It does not solve the type casting to number for keys.)
var object = { 0: [1, 2, 3, 4] },
result = Object.keys(object).reduce(function (r, k) {
return r.concat(k, object[k]);
}, []);
console.log(result);