Need help recursively iterating through all levels of a Javascript object - javascript

I am trying to create an object, and within this object will be the name and an array of other objects under children. Really I want to create a hierarchy from another object.
I have tried to create a recursive function but what I end up with is a vertical slice rather than the whole picture. I am unsure how to adjust my recursion to go back add iterate through the other horizontal objects.
buildHierarchy(json) {
console.log("Entered Build Hierarchy");
let newObject;
newObject = this.buildChildren(json);
console.log(newObject);
return newObject
}
buildChildren(json) {
let returnObject;
for (var key in json) {
returnObject = {
name: key,
children: []
};
var subObject = json[key];
if (Array.isArray(subObject)) {
returnObject = {
name: key,
_proficiency: subObject
}
} else {
returnObject["children"].push(this.buildChildren(subObject))
}
}
return returnObject;
}
Imagine you have this json file below
{users:
{sandy: {
posts: [
{ title: 'Bar', comments: [ 'Ok' ] },
]
followers: [
{ name: 'Foo' },
]
}
ron: {
photos: [
{ title: 'Foo', comments: [ 'Ok' ] },
]
}
}
}
I am looking for something like this...
{
name: "users",
children: [
{
name: "sandy",
children: [
{
name: "posts",
children: [
{
name: "Bar",
comments: "OK"
}],
{ name: "followers"
children: [
{
name: "Foo"
}
]
}
}
]
},
{
name: "ron",
photos: [
{
name: "photos",
children: [
{
name: "Foo",
comments: "OK"
}
]
}
]
}
]
}

From what I see as the output I'm making these inferences:
If the child object is an array, it is blindly copied to children key
If the child element is an object, then they are changed to {name: <KEY>, children: <VALUE>}
function buildChildren(json) {
let returnObject = [];
if (typeof json !== 'object') {
return json;
}
for (var key in json) {
if (Array.isArray(json)) {
returnObject.push(buildChildren(json[key]));
} else {
returnObject.push({
name: key,
children: buildChildren(json[key])
});
}
}
return returnObject;
}

function buildHierarchy(json) {
console.log("Entered Build Hierarchy");
let newObject;
newObject = buildChildren(json);
console.log(newObject);
}
function buildChildren(json) {
if (Array.isArray(json)) {
return {
_proficiency: json
}
}
var children = Object.keys(json);
let final = [];
for (var i = 0; count = children.length, i < count; i++) {
let result = {
name: children[i]
}
let d = buildChildren(json[children[i]]);
if (d._proficiency) {
result._proficiency = d._proficiency;
} else {
result.children = d;
}
final.push(result);
}
return final;
}

Related

Javascript create regex for filter?

I'm receiving an object like this from the front-end app:
{
name: "Red boys"
category: "Fashion"
subCategory: [
{ name: "sub"},
{ name: "Hub"}
{ name: "Mub"}
// Here it is not static, Here can more or less object in the array
]
}
I have to create a new object from it:
{ category: {name: "Fashion", subCategory: {name: {$in: ["sub", "Hub", "Mub"]}}}}
Here is My Code-
let args = {};
for (let key in filters) {
if (filters[key].length > 0) {
if (key === "category") {
args["category"] = {
name: filters['category'],
// Here I have to check if subCatgory has some value, then create subcategory field
subCategory: {
name: {
$in: [] // Here I can't what I have to wrie
}
}
}
}
}
}
console.log(args);
Pleae help me. I can't understand this functionality. I search but I can get any solutions.
You can destructure the original object, and then restructure the properties from it into a new object. For the sub categories you can map over the array to create an array of objects.
const fe = {
name: 'Red boys',
category: 'Fashion',
subCategory: [
{ name: 'sub' },
{ name: 'Hub' },
{ name: 'Mub' }
]
};
// Get the category and subcategory from the
// object passed from the front-end app
const { category, subCategory } = fe;
// And create a new object
const be = {
category: {
name: 'Fashion',
subCategory: {
name: {
$in: subCategory.map(s => s.name)
}
}
}
};
console.log(be);
Here is the simple solution to the objective:
out.subCategory.name['$in'] = in.subCategory.map( item => item.name );
const inputData = {
name: "Red boys",
category: "Fashion",
subCategory: [
{ name: "sub"},
{ name: "Hub"},
{ name: "Mub"}
]
};
function convertToDesired ( obj ) {
const output = {
category: {
name: obj.category,
subCategory: {
name: {
$in: obj.subCategory.map( item => item.name )
}
}
}
};
return output;
}
console.log(convertToDesired(inputData))
#Suvana
Based on your implementation here is how you can achieve the desired output.
I attached the fiddle code as well.
https://jsfiddle.net/xco7vkn8/1/
for (let key in filters) {
if (filters[key].length > 0) {
if (key === "category") {
args["category"] = {
name: filters['category'],
subcategory:{},
}
}
else if(key ==="subCategory"){
if(filters['subCategory'].length>0){
new_array = [];
filters['subCategory'].forEach(function (item, index) {
new_array.push(item.name);
});
args["category"].subcategory={
name:{
$in:new_array
}
}
}
}
}
}
console.log(args);

How can I reach inside nested object in javascript?

How do I reach isBoatOwner so I can return it's value in a array?
My code is returning undefined.
pluck(
[
{ name: "Tim", isBoatOwner: true },
{ name: "Matt", isBoatOwner: false },
{ name: "Elie" }
],
"isBoatOwner"
);
function pluck(defObj, key) {
let arr = [];
for (let i = 0; i < defObj.length; i++) {
if (Object.keys(defObj[i]) == key) {
arr.push(defObj[i][key]);
} else {
arr.push(undefined);
}
}
return arr.flat();
}
All you need is a simple .map():
console.log(pluck(
[
{ name: "Tim", isBoatOwner: true },
{ name: "Matt", isBoatOwner: false },
{ name: "Elie" }
],
"isBoatOwner"
));
function pluck(defObj, key) {
return defObj.map(function (obj) {
return obj[key];
});
}
So the above function collects all the values of isBoatOwner from the array and sends it as an array of values.
[
true,
false,
undefined
]
In your code you are trying to compare an array to a string to see if the property exists. That is never going to match
function pluck(defObj, key) {
let arr = [];
for (let i = 0; i < defObj.length; i++) {
// if (Object.keys(defObj[i]) == key) {
if (defObj[i][key] !== undefined) {
arr.push(defObj[i][key]);
} else {
arr.push(undefined);
}
}
return arr.flat();
}
var result = pluck(
[{
name: "Tim",
isBoatOwner: true
},
{
name: "Matt",
isBoatOwner: false
},
{
name: "Elie"
}
],
"isBoatOwner"
);
console.log(result);
But the check does not make too much sense since you are pushing undefined into it. So it could just be
function pluck(defObj, key) {
let arr = [];
for (let i = 0; i < defObj.length; i++) {
arr.push(defObj[i][key]);
}
return arr.flat();
}
var result = pluck(
[{
name: "Tim",
isBoatOwner: true
},
{
name: "Matt",
isBoatOwner: false
},
{
name: "Elie"
}
],
"isBoatOwner"
);
console.log(result);
Modern approach is just map
function pluck(defObj, key) {
// return defObj.map(function(item) { return item[key]; });
return defObj.map(item => item[key]);
}
var result = pluck(
[{
name: "Tim",
isBoatOwner: true
},
{
name: "Matt",
isBoatOwner: false
},
{
name: "Elie"
}
],
"isBoatOwner"
);
console.log(result);

how to find object using recursion in javascript?

let tree = {
name: "A",
children: [
{
name: 'A-1',
children: [
{name: "A-1-A"},
{name: "A-1-B"},
]
},
{
name: 'B-1',
children: [
{
name: "B-1-A",
children: [
{name: "B-11-A"},
{name: "B-11-B"}
]
},
{name: "B-1-B"},
]
},
]
};
I am trying to find object from tree object using recursion .
when I call like this searchFn(tree,'A-1') it should return {
name: 'A-1',
children: [
{name: "A-1-A"},
{name: "A-1-B"},
]
} object
it I call like this searchFn(tree,'A-1-A') it should return this
{name: "A-1-A"}
I tried like this but not working
function searchFn(obj ,searchText){
if(obj.name === searchText) return obj
if(obj.children.length > 0){
return searchFn(obj.children.pop(),searchText)
}
return null
}
You need to iterate the children of the object and take a variable for the result.
function searchFn(object, searchText) {
var result;
if (object.name === searchText) return object;
(object.children || []).some(o => result = searchFn(o, searchText));
return result || null;
}
let tree = { name: "A", children: [{ name: 'A-1', children: [{ name: "A-1-A" }, { name: "A-1-B" }] }, { name: 'B-1', children: [{ name: "B-1-A", children: [{ name: "B-11-A" }, { name: "B-11-B" }] }, { name: "B-1-B" }] }] };
console.log(searchFn(tree, 'foo'));
console.log(searchFn(tree, 'A-1'));
.as-console-wrapper { max-height: 100% !important; top: 0; }
First, you should create a class for readability. Then you should have a loop inside the function that iterates over the children and only returns if a child is found.
class Node {
static fromStruct = (struct) => {
const tree = new Node(struct.name);
if(!struct.children) return tree;
for(const child of struct.children) {
tree.children.push(Node.fromStruct(child));
}
return tree;
}
constructor(name){
this.name = name;
this.children = [];
}
addChild = (parentName, childName) => {
const parent = this.searchFn(parentName);
if(!parent) throw new Error("Parent not found");
parent.children.push(new Node(childName));
}
searchFn = (name) => {
if(this.name === name) return this;
for(const child of this.children) {
const found = child.searchFn(name);
if(found !== null) return found;
}
return null;
}
}
const data = {
name: "A",
children: [
{
name: 'A-1',
children: [
{name: "A-1-A"},
{name: "A-1-B"},
]
},
{
name: 'B-1',
children: [
{
name: "B-1-A",
children: [
{name: "B-11-A"},
{name: "B-11-B"}
]
},
{name: "B-1-B"},
]
},
]
};
const tree = Node.fromStruct(data);
console.log(tree.searchFn("A-1-A"));
const tree = {"name":"A","children":[{"name":"A-1","children":[{"name":"A-1-A"},{"name":"A-1-B"}]},{"name":"B-1","children":[{"name":"B-1-A","children":[{"name":"B-11-A"},{"name":"B-11-B"}]},{"name":"B-1-B"}]}]}
const searchFn = (tree, name) => {
let result = null;
if (typeof tree !== "object") return result;
if (tree.name === name) return tree;
if (tree.children && tree.children.length) {
tree.children.some(data => (result = searchFn(data, name)));
}
return result;
};
console.log(searchFn(tree, "A-1-A"));
console.log(searchFn(tree, "A-1"));
console.log(searchFn(tree, ""));
.as-console-row {color: blue!important}
You can try something like this
let tree = { name: "A", children: [{ name: 'A-1', children: [{ name: "A-1-A" }, { name: "A-1-B" }] }, { name: 'B-1', children: [{ name: "B-1-A", children: [{ name: "B-11-A" }, { name: "B-11-B" }] }, { name: "B-1-B" }] }] };
function searchFn(obj, text){
if(obj.name === text) return obj
else{
if(obj && obj.children && Array.isArray(obj.children)){
for(let value of obj.children){
if(searchFn(value, text)){
return searchFn(value, text)
}
}
}
}
return null
}
console.log(searchFn(tree, 'A-1'))
console.log(searchFn(tree, 'A-1-A'))
console.log(searchFn(tree, 'A-A-A'))
The problem with your function is that it only checks for the popped element from the array in the children property of the passed object, and not the other elements. Try this:
function searchFn(obj ,searchText) {
if(obj.name === searchText) return obj;
if(obj.children) {
for (let x of obj.children) {
let y = searchFn(x,searchText);
if (y)
return y;
}
}
return null;
}

How to render recursive components outside of parent component in Vue.js?

I have a tree data structure, and i need to recursively render it
const tree = [
{
name: 'hello',
children: [
{
name: 'world',
children: [
{
name: 'bye'
}
]
}
]
}
];
the problem is that this component should be inside table as table-rows, so it cannot be nested in DOM inside each other
This is what it looks like
https://jsfiddle.net/zw4mydxb/2/
and this is the result i need
<tr>hello</tr>
<tr>world</tr>
<tr>bye</tr>
is it even possible to achieve with recursive components and without changing data structure?
You can use recursion for this, Following code snippet will help you.
const tree = [
{
name: "hello",
children: [
{
name: "world",
children: [
{
name: "bye"
}
]
},
{
name: "hola"
}
]
},
{
name: "how",
children: [
{
name: "is",
children: [
{
name: "life"
}
]
}
]
}
];
function getData(tree) {
if (tree && typeof tree[0].children === "undefined") return tree[0].name;
var outputString = [];
for (let i = 0; i < tree.length; i++) {
if (typeof tree[i].children != "undefined") {
outputString.push(tree[i].name, getData(tree[i].children));
} else {
outputString.push(tree[i].name);
}
}
return outputString.toString().split(",");
}
console.log(getData(tree));
Now you have an array of name and you can iterate this array.

looping through a json tree object and create new array

Is there a way good way JS/ES6 to loop through an object and it's children and creating new object tree array.
I have this json tree object:
[
{
id: "001",
deparmentsIds: [
"002",
"003"
],
details: {
parentDeparmentsId: null,
name: "Top"
}
},
{
id: "002",
deparmentsIds:[
"004"
],
details: {
parentDeparmentsId: ["001"],
name: "Operations"
}
},
{
id: "003",
deparmentsIds:[]
details: {
parentDeparmentsId: ["001"],
name: "Support"
}
},
{
id: "004",
deparmentsIds:[]
details: {
parentDeparmentsId: ["002"],
name: "Support operations"
}
}
]
I want to create new object array tree that looks like this:
You could create recursive function with reduce and map method to create nested object structure.
const data = [{"id":"001","deparmentsIds":["002","003"],"details":{"parentDeparmentsId":null,"name":"Top"}},{"id":"002","deparmentsIds":["004"],"details":{"parentDeparmentsId":"001","name":"Operations"}},{"id":"003","deparmentsIds":[],"details":{"parentDeparmentsId":"001","name":"Support"}},{"id":"004","deparmentsIds":[],"details":{"parentDeparmentsId":"002","name":"Support operations"}}]
function tree(input, parentId) {
return input.reduce((r, e) => {
if (e.id == parentId || parentId == undefined && e.details.parentDeparmentsId == null) {
const children = [].concat(...e.deparmentsIds.map(id => tree(input, id)))
const obj = {
[e.details.name]: children
}
r.push(obj)
}
return r;
}, [])
}
const result = tree(data)
console.log(result)
You could collect all information in an object with a single loop and return only the nodes with no parent.
function getTree(data, root) {
var o = {};
data.forEach(({ id, details: { parentDeparmentsId: parent, name } }) => {
var temp = { id, name };
if (o[id] && o[id].children) {
temp.children = o[id].children;
}
o[id] = temp;
o[parent] = o[parent] || {};
o[parent].children = o[parent].children || [];
o[parent].children.push(temp);
});
return o[root].children;
}
var data = [{ id: "001", deparmentsIds: ["002", "003"], details: { parentDeparmentsId: null, name: "Top" } }, { id: "002", deparmentsIds: ["004"], details: { parentDeparmentsId: ["001"], name: "Operations" } }, { id: "003", deparmentsIds: [], details: { parentDeparmentsId: ["001"], name: "Support" } }, { id: "004", deparmentsIds: [], details: { parentDeparmentsId: ["002"], name: "Support operations" } }],
tree = getTree(data, null);
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Categories