-
-
Save tushar-borole/567c1d22ca8d5498cbc0 to your computer and use it in GitHub Desktop.
var data = { | |
"name": "root", | |
"contents": [ | |
{ | |
"name": "A", | |
"contents": [ | |
{ | |
"name": "fileA1", | |
"contents": [] | |
} | |
] | |
}, | |
{ | |
"name": "B", | |
"contents": [ | |
{ | |
"name": "dirB1", | |
"contents": [ | |
{ | |
"name": "fileBB1", | |
"contents": [] | |
} | |
] | |
}, | |
{ | |
"name": "fileB1", | |
"contents": [] | |
} | |
] | |
} | |
] | |
}; | |
traverse(data); | |
function traverse(obj) { | |
_.forIn(obj, function (val, key) { | |
console.log(key, val); | |
if (_.isArray(val)) { | |
val.forEach(function(el) { | |
if (_.isObject(el)) { | |
traverse(el); | |
} | |
}); | |
} | |
if (_.isObject(key)) { | |
traverse(obj[key]); | |
} | |
}); | |
} |
Pure javascript solution:
const traverse = (obj) => {
for (let k in obj) {
if (obj[k] && typeof obj[k] === 'object') {
traverse(obj[k])
} else {
// Do something with obj[k]
}
}
}
https://www.npmjs.com/package/deepdash
_.eachDeep(obj, (value, key, path, depth, parent, parentKey, parentPath) => {
//do
});
Hey man, thanks for the traversal algorithm, the pure javascript one. It really helped a lot!
Pure javascript solution:
const traverse = (obj) => { for (let k in obj) { if (obj[k] && typeof obj[k] === 'object') { traverse(obj[k]) } else { // Do something with obj[k] } } }
Thanks @fugroup .
const traverse = (obj) => {
for (let k in obj) {
if (obj[k] && typeof obj[k] === 'object') {
traverse(obj[k])
} else {
// Do something with obj[k]
}
}
}
const traverse = (obj) => {
for (let k in obj) {
if (obj.hasOwnProperty(k) && obj[k] && typeof obj[k] === 'object') {
traverse(obj[k])
} else {
// Do something with obj[k]
}
}
}
Pure JS function to execute callback on every match
async deepTraversal(obj, pKey, callback) {
Object.keys(obj).forEach((vKey) => {
if (vKey === pKey) {
callback(obj[vKey]);
}
if (typeof obj[vKey] === "object") {
iterate(obj[vKey]);
}
});
}
iterate(obj[vKey]);
iterate
is not defined. deepTraversal
perhaps .... otherwise there is no recursion ;)
Here's a funny one which works for serializable/deserializable types:
function traverse(obj, f) {
return JSON.parse(JSON.stringify(obj), f);
}
JSON.parse calls f on every key-value pair, and what you return is what the new value will be.
Here's a funny one which works for serializable/deserializable types:
function traverse(obj, f) { return JSON.parse(JSON.stringify(obj), f); }
JSON.parse calls f on every key-value pair, and what you return is what the new value will be.
👍👍👍
export const DELETE = Symbol('DELETE');
/**
* Traverse an object and apply a transformation function to each value.
* The transformation function is called with the value, the key and the key path.
*
* The transformation function can return a new value or the same value.
* If the transformation function returns a new value, the value in the object is replaced with the new value.
*
* The transformation function can return an object.
* If the transformation function returns an object, the object is traversed as well.
*
* Warning: The transformation could loop infinitely if it always returns an object.
*
* @param obj { object } - the object to traverse
* @param transform { (value: unknown, key: string, keyPath: string) => unknown } - a function that transforms the value, the key and the key path
*/
export async function traverse(obj, transform) {
/**
* @type { object[] }
*/
const objectStack = [obj];
/**
* @type { string[] }
*/
const keysStack = []
while (objectStack.length > 0) {
const obj = objectStack.pop();
if (obj) {
for (const key in obj) {
keysStack.push(key);
const keyPath = keysStack.join('.');
const value = obj[key];
const transformed = transform(value, key, keyPath);
if(transformed === DELETE){
delete obj[key];
keysStack.pop();
continue;
}
if (transformed !== value) {
obj[key] = transformed;
}
if (typeof transformed === 'object' && transformed !== null) {
objectStack.push(transformed);
} else {
keysStack.pop();
}
}
}
}
}
/**
* Traverse an object and apply a transformation function to each value.
* The transformation function is called with the value, the key and the key path.
*
* The transformation function can return a new value or the same value.
* If the transformation function returns a new value, the value in the object is replaced with the new value.
*
* The transformation function can return an object.
* If the transformation function returns an object, the object is traversed as well.
*
* The transformation function can return a promise.
* If the transformation function returns a promise, the promise is awaited and the resolved value is used.
*
* Warning: The transformation could loop infinitely if it always returns an object.
*
* @param obj { object } - the object to traverse
* @param transform { (value: unknown, key: string, keyPath: string) => unknown | Promise<unknown> } - a function that transforms the value, the key and the key path
* @returns
**/
export async function traverseAsync(obj, transform) {
/**
* @type { object[] }
*/
const objectStack = [obj];
/**
* @type { string[] }
*/
const keysStack = []
while (objectStack.length > 0) {
const obj = objectStack.pop();
if (obj) {
for (const key in obj) {
keysStack.push(key);
const keyPath = keysStack.join('.');
const value = obj[key];
const awaitedValue = await value;
const transformed = await transform(awaitedValue, key, keyPath);
if(transformed === DELETE){
delete obj[key];
keysStack.pop();
continue;
}
if(value !== transformed){
obj[key] = transformed;
}
if (typeof transformed === 'object' && transformed !== null) {
objectStack.push(transformed);
} else {
keysStack.pop();
}
}
}
}
}
const obj = { a: 1, b: { c: [{ a: 2 }, { d: 20}] } }
traverse(obj, (value, key, keyPath) => {
if(keyPath === 'a'){
return DELETE;
}
return value
})
obj
const asyncObj = { a: 1, b: { c: Promise.resolve([{ a: 2 }]) } }
traverseAsync(asyncObj, (value, key, keyPath) => {
if(keyPath === 'a'){
return DELETE;
}
return value
}).then(() => {
asyncObj
})
I came up with this, which is a little different. Am I missing something?