Last active
October 11, 2018 21:43
-
-
Save touhidrahman/d8c0120c7ef92ac5a1f09ce1cd6d1f02 to your computer and use it in GitHub Desktop.
Flatten a javascript object in specified structure (see comment block)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Run file | |
* | |
* `tsc flatten.ts && node flatten.js` | |
* | |
* Given following object: | |
{ | |
test: "test1", | |
same: "same", | |
nested: { | |
x: { | |
p: 3, | |
q: { r: 6 } | |
} | |
}, | |
arr: [ 1, 2, 3], | |
arrObjs: [ | |
{ y: "y"}, | |
{ z: "a"} | |
] | |
} | |
* | |
* Should output: | |
* | |
[ { path: [ 'test' ], value: 'test1' }, | |
{ path: [ 'same' ], value: 'same' }, | |
{ path: [ 'arr' ], value: [ 1, 2, 3 ] }, | |
{ path: [ 'arrObjs' ], value: [ [Object], [Object] ] }, | |
{ path: [ 'nested', 'x', 'p' ], value: 3 }, | |
{ path: [ 'nested', 'x', 'q', 'r' ], value: 6 } ] | |
* | |
*/ | |
export interface PathValue { | |
path: Array<string>, | |
value: any, | |
} | |
export class Flattener { | |
isObject(obj: Object): boolean { | |
return typeof obj === 'object' && !Array.isArray(obj) | |
} | |
isPrimitiveOrArray(obj: Object): boolean { | |
return typeof obj !== 'object' || ( Array.isArray(obj) && obj.length > 0) | |
} | |
/** | |
* Input { a: { b: 1}} | |
* Return [ { path: 'a', value: {b:1} } ] | |
*/ | |
flattenOneLevel(obj: Object, prePath: Array<string> = []): Array<PathValue> { | |
if (!this.isObject(obj)) return | |
const result: Array<PathValue> = [] | |
Object.keys(obj).forEach(key => { | |
result.push({ path: [...prePath, key], value: obj[key] }) | |
}) | |
return result | |
} | |
flattenDeep(valueMap: Array<PathValue>): Array<PathValue> { | |
if (!valueMap) return | |
const result = valueMap.filter( | |
x => !!x.value && this.isPrimitiveOrArray(x.value) | |
) | |
valueMap | |
.filter(x => this.isObject(x.value)) | |
.forEach(it => { | |
if (it.value) | |
this.flatten(it.value, it.path).forEach(y => result.push(y)) | |
}) | |
return result | |
} | |
flatten(obj: Object, prePath?: Array<string>): Array<PathValue> { | |
if (this.isObject(obj)) | |
return this.flattenDeep(this.flattenOneLevel(obj, prePath)) | |
} | |
} | |
/******************* | |
* Tests * | |
*******************/ | |
let main = new Flattener() | |
const c = { | |
test: "test1", | |
same: "same", | |
nested: { | |
x: { | |
p: 3, | |
q: { r: 6 } | |
} | |
}, | |
arr: [ 1, 2, 3], | |
arrObjs: [ | |
{ y: "y"}, | |
{ z: "a"} | |
] | |
} | |
const res = main.flatten(c) | |
console.log(res) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment