Related
I have an array of regions the highest region has key: 10 and parent_id: null and I want to restructure this array to return a tree.
Regions tree should look like if the input is [10]
Egypt
Zone 1
Tagamo3
Giza
Helwan
Fayoum
Zone 2
Gesr ElSuis
test
Delta
Mohandeseen
Down Town
Array:
[
{
"key": 1,
"title": "Zone 1",
"parent_id": 10
},
{
"key": 2,
"title": "Zone 2",
"parent_id": 10
},
{
"key": 3,
"title": "Tagamo3",
"parent_id": 1
},
{
"key": 4,
"title": "Gesr ElSuis",
"parent_id": 2
},
{
"key": 5,
"title": "Delta",
"parent_id": 2
},
{
"key": 6,
"title": "Mohandeseen",
"parent_id": 2
},
{
"key": 7,
"title": "Giza",
"parent_id": 1
},
{
"key": 8,
"title": "Helwan",
"parent_id": 1
},
{
"key": 9,
"title": "Down Town",
"parent_id": 2
},
{
"key": 10,
"title": "Egypt",
"parent_id": null
},
{
"key": 11,
"title": "Fayoum",
"parent_id": 1
},
{
"key": 12,
"title": "test",
"parent_id": 4
}
]
The output I want to achieve if input is [10]:
[
{
"key": 10,
"title": "Egypt",
"parent_id": null,
"children": [
{
"key": 1,
"title": "Zone 1",
"parent_id": 10,
"children": [
{
"key": 3,
"title": "Tagamo3",
"parent_id": 1,
"children": []
},
{
"key": 7,
"title": "Giza",
"parent_id": 1,
"children": []
},
{
"key": 8,
"title": "Helwan",
"parent_id": 1,
"children": []
},
{
"key": 11,
"title": "Fayoum",
"parent_id": 1,
"children": []
}
]
},
{
"key": 2,
"title": "Zone 2",
"parent_id": 10,
"children": [
{
"key": 4,
"title": "Gesr ElSuis",
"parent_id": 2,
"children": [
{
"key": 12,
"title": "test",
"parent_id": 4,
"children": []
}
]
},
{
"key": 5,
"title": "Delta",
"parent_id": 2,
"children": []
},
{
"key": 6,
"title": "Mohandeseen",
"parent_id": 2,
"children": []
},
{
"key": 9,
"title": "Down Town",
"parent_id": 2,
"children": []
}
]
}
]
}
]
Regions tree should look like if the input is [1,2]
Zone 1
Tagamo3
Giza
Helwan
Fayoum
Zone 2
Gesr ElSuis
test
Delta
Mohandeseen
Down Town
Regions tree should look like if the input is [1]
Zone 1
Tagamo3
Giza
Helwan
Fayoum
May not be the most optimized, but I gave it a try:
const arr = [{key:1,title:"Zone 1",parent_id:10},{key:2,title:"Zone 2",parent_id:10},{key:3,title:"Tagamo3",parent_id:1},{key:4,title:"Gesr ElSuis",parent_id:2},{key:5,title:"Delta",parent_id:2},{key:6,title:"Mohandeseen",parent_id:2},{key:7,title:"Giza",parent_id:1},{key:8,title:"Helwan",parent_id:1},{key:9,title:"Down Town",parent_id:2},{key:10,title:"Egypt",parent_id:null},{key:11,title:"Fayoum",parent_id:1},{key:12,title:"test",parent_id:4}];
const buildTree = key => arr.filter(x => x.parent_id === key)
.map(x => ({ ...x, children: buildTree(x.key) }));
console.log(buildTree(null));
To build multiple trees, this could work:
const arr = [{key:1,title:"Zone 1",parent_id:10},{key:2,title:"Zone 2",parent_id:10},{key:3,title:"Tagamo3",parent_id:1},{key:4,title:"Gesr ElSuis",parent_id:2},{key:5,title:"Delta",parent_id:2},{key:6,title:"Mohandeseen",parent_id:2},{key:7,title:"Giza",parent_id:1},{key:8,title:"Helwan",parent_id:1},{key:9,title:"Down Town",parent_id:2},{key:10,title:"Egypt",parent_id:null},{key:11,title:"Fayoum",parent_id:1},{key:12,title:"test",parent_id:4}];
const buildNode = x => ({...x, children: buildTree(x.key)});
const buildTree = key => arr.filter(x => x.parent_id === key)
.map(buildNode);
const buildTrees = keys => arr.filter(x => keys.includes(x.key))
.map(buildNode);
console.log(buildTrees([1, 2]));
based on jcalz snippet, but requires only a single pass over the input array.
const arr = [{key:1,title:"Zone 1",parent_id:10},{key:2,title:"Zone 2",parent_id:10},{key:3,title:"Tagamo3",parent_id:1},{key:4,title:"Gesr ElSuis",parent_id:2},{key:5,title:"Delta",parent_id:2},{key:6,title:"Mohandeseen",parent_id:2},{key:7,title:"Giza",parent_id:1},{key:8,title:"Helwan",parent_id:1},{key:9,title:"Down Town",parent_id:2},{key:10,title:"Egypt",parent_id:null},{key:11,title:"Fayoum",parent_id:1},{key:12,title:"test",parent_id:4}];
/*const lookup: Record<number|"roots", Tree[]> = { roots: [] };*/
const lookup = { roots: [] };
for (const item of arr) {
// get or create the "children" array for my parent.
// parent may not be known yet, but I'm already collecting its children, my siblings.
const siblings = lookup[item.parent_id ?? "roots"] ??= [];
// add myself to that children array.
siblings.push({
...item,
// get or create my children array.
children: lookup[item.key] ??= []
});
}
// it's up to you to handle `lookup.roots.length !== 1`
console.log(lookup.roots);
.as-console-wrapper{top:0;max-height:100%!important}
Hi i want to get children tree from a category list.
here is my input data
[
{ "parent_id": -1, "name": "Toothpaste", "id": 99 },
{
"parent_id": -1,
"name": "Cake",
"id": 3
},
{
"parent_id": 3,
"name": "Chocolate Cake",
"id": 4
},
{
"parent_id": 3,
"name": "Walnut Cake",
"id": 5
},
{
"parent_id": 4,
"name": "Chocolate Cake mixin 1",
"id": 6
}
]
my desired output will look like below one
[ { "parent_id": -1, "name": "Toothpaste", "id": 99 },
{
"parent_id": -1,
"name": "Cake",
"id": 3,
"children":[
{
"parent_id": 3,
"name": "Chocolate Cake",
"id": 4,
"children":[ //<--- observe this one not there in my output
{
"parent_id": 4,
"name": "Chocolate Cake mixin 1",
"id": 6
}
]
},
{
"parent_id": 3,
"name": "Walnut Cake",
"id": 5
}
],
}
]
The problem i'm facing is that i'm unable to push data into 2nd level i,e chocolate cake is having children but i'm unable to push that into chocolate cake children
Note: solution must work for any level of nesting
here is what i have tried
function getChildrenTree(childList){
let childMap = {};
for(let i = 0; i < childList.length; i++){
if(childList[i].parent_id === -1)
childMap[childList[i].id] = {name:childList[i].name,children:[]};
}
for(let i = 0; i < childList.length; i++){
if(childMap && childMap.hasOwnProperty(childList[i].parent_id) && childMap[childList[i].parent_id].hasOwnProperty('children')) childMap[childList[i].parent_id].children.push(childList[i]);
}
return Object.values(childMap);
}
getChildrenTree([ { "parent_id": -1, "name": "Toothpaste", "id": 99 },{ "parent_id": -1, "name": "Cake", "id": 3 }, { "parent_id": 3, "name": "Chocolate Cake", "id": 4 }, { "parent_id": 3, "name": "Walnut Cake", "id": 5 }, { "parent_id": 4, "name": "Chocolate Cake mixin 1", "id": 6 } ])
Here's an approach you can try.
const flat = [
{ "parent_id": -1, "name": "Toothpaste", "id": 99 },
{
"parent_id": -1,
"name": "Cake",
"id": 3
},
{
"parent_id": 3,
"name": "Chocolate Cake",
"id": 4
},
{
"parent_id": 3,
"name": "Walnut Cake",
"id": 5
},
{
"parent_id": 4,
"name": "Chocolate Cake mixin 1",
"id": 6
}
];
const makeTree = (arr, parent) => {
const branch = arr.filter(node => node.parent_id === parent);
branch.forEach(node => {
const children = makeTree(arr, node.id);
if (children.length) {
node.children = children;
}
});
return branch;
};
const tree = makeTree(flat, -1);
console.log(tree);
You could take a single loop and and object for collecting the nodes and return a tree by taking all children from the root node.
const
buildTree = (data, root) => {
var t = {};
data.forEach(o => {
Object.assign(t[o.id] = t[o.id] || {}, o);
((t[o.parent_id] ??= {}).children ??= []).push(t[o.id]);
});
return t[root].children
},
data = [{ parent_id: -1, name: "Toothpaste", id: 99 }, { parent_id: -1, name: "Cake", id: 3 }, { parent_id: 3, name: "Chocolate Cake", id: 4 }, { parent_id: 3, name: "Walnut Cake", id: 5 }, { parent_id: 4, name: "Chocolate Cake mixin 1", id: 6 }],
tree = buildTree(data, -1);
console.log(tree);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I need to convert below unformatted JSON format into formatted input. We need to find id's similar to parent id for different items inside array element of object and then need to push it into children to that id. Below is my code that needs to transform
Input
{
"0": [
{
"id": 10,
"title": "House",
"level": 0,
"children": [],
"parent_id": null
}
],
"1": [
{
"id": 12,
"title": "Red Roof",
"level": 1,
"children": [],
"parent_id": 10
},
{
"id": 18,
"title": "Blue Roof",
"level": 1,
"children": [],
"parent_id": 10
}
],
"2": [
{
"id": 17,
"title": "Blue Windoww",
"level": 2,
"children": [],
"parent_id": 12
},
{
"id": 16,
"title": "Door",
"level": 2,
"children": [],
"parent_id": 13
}
]
}
Output
[
{
"id": 10,
"title": "House",
"level": 0,
"children": [
{
"id": 12,
"title": "RedRoofff",
"level": 1,
"children": [
{
"id": 17,
"title": "Blue Windoww",
"level": 2,
"children": [],
"parent_id": 12
}
],
"parent_id": 10
},
{
"id": 18,
"title": "Blue Roof",
"level": 1,
"children": [],
"parent_id": 10
},
{
"id": 13,
"title": "Wall",
"level": 1,
"children": [
{
"id": 16,
"title": "Door",
"level": 2,
"children": [],
"parent_id": 13
}
],
"parent_id": 10
}
],
"parent_id": null
}
]
Please find the solution to above problem.
first, we track the node with Id and then we update the children array like this.
(btw, your input have a missing node, 13)
const input = {
"0": [{
"id": 10,
"title": "House",
"level": 0,
"children": [],
"parent_id": null
}, {
"id": 13,
"title": "Wall",
"level": 0,
"children": [],
"parent_id": null
}],
"1": [{
"id": 12,
"title": "Red Roof",
"level": 1,
"children": [],
"parent_id": 10
},
{
"id": 18,
"title": "Blue Roof",
"level": 1,
"children": [],
"parent_id": 10
},
],
"2": [{
"id": 17,
"title": "Blue Windoww",
"level": 2,
"children": [],
"parent_id": 12
},
{
"id": 16,
"title": "Door",
"level": 2,
"children": [],
"parent_id": 13
},
]
};
const results = [];
const mapId2Node = Object.values(input).reduce((acc, vals) => {
vals.forEach(val => {
acc[val.id] = val;
if (val.parent_id === null) {
results.push(val);
}
});
return acc;
}, {});
Object.values(input).forEach(vals => {
vals.forEach(val => {
if (val.parent_id !== null) {
mapId2Node[val.parent_id].children.push(val);
}
});
});
conosle.log(results);
I have following JavaScript Array
business: [{
"id": 22,
"name": "Private",
"max_mem": 0,
"gen_roomtype_id": 4,
"status": 1,
"type": 0,
"set_value": 1
},
{
"id": 6,
"name": "Standard ward",
"max_mem": 0,
"gen_roomtype_id": 2,
"status": 1,
"type": 0,
"set_value": 1
},
{
"id": 7,
"name": "Semi Private",
"max_mem": 0,
"gen_roomtype_id": 3,
"status": 1,
"type": 0,
"set_value": 1
}],
"gen": [{
"id": 5,
"name": "laboratory",
"description": "",
"sharing": 0,
"set_value": 2
}],
And i have a idArray as following
idArray: [5, 7]
i would like to know whether the idArray values are belongs to "gen" Array or
"business" Array.
You can use the function every
This approach assumes the input data is an object.
var obj = { business: [{ "id": 5, "name": "Private", "max_mem": 0, "gen_roomtype_id": 4, "status": 1, "type": 0, "set_value": 1 }, { "id": 6, "name": "Standard ward", "max_mem": 0, "gen_roomtype_id": 2, "status": 1, "type": 0, "set_value": 1 }, { "id": 7, "name": "Semi Private", "max_mem": 0, "gen_roomtype_id": 3, "status": 1, "type": 0, "set_value": 1 } ], "gen": [{ "id": 5, "name": "laboratory", "description": "", "sharing": 0, "set_value": 2 }]
};
var idArray = [5, 7];
var resultBusiness = idArray.every(n => obj.business.some(b => b.id === n));
var resultGen = idArray.every(n => obj.gen.some(b => b.id === n));
console.log("All in business: ", resultBusiness);
console.log("All in Gen: ", resultGen);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I'm a bit mentally stuck in processing some data in JS with that I'm outputting from my API.
What the backend is outputing is a category list that can be nested up to N-th level.
What I'm trying to do is generate a nice nested structure for them so that they represent the JSON structure but in the DOM:
<div>
Women's Fashion
<div>
Women's Clothes
<div>Dresses</div>
<div>Watches</div>
<div>Etc.</div>
</div>
<div>
Watches
</div>
<div>
Jewellery
<div>Swarowski</div>
<div>Other</div>
</div>
</div>
What's a good way for me to achieve this structure?
Here is a sample of the data I'm outputing. The key stuff here is that each Category can have a M-number of subcategories and the end-depth is not actually limited.
{
"results": [
{
"id": 1,
"name": "Women's Fashion",
"hashtag": "#womensfashion",
"parent_id": null,
"parents_list": [],
"product_count": 9466,
"subcategories": [
{
"id": 2,
"name": "Womens Clothes",
"hashtag": "#womensclothes",
"parent_id": 1,
"parents_list": [
1
],
"product_count": 2940,
"subcategories": [
{
"id": 3,
"name": "Dresses",
"hashtag": "#dresses",
"parent_id": 2,
"parents_list": [
2,
1
],
"product_count": null,
"subcategories": []
},
{
"id": 4,
"name": "Tops",
"hashtag": "#womenstops",
"parent_id": 2,
"parents_list": [
2,
1
],
"product_count": null,
"subcategories": []
},
{
"id": 5,
"name": "Outwear",
"hashtag": "#womensoutwear",
"parent_id": 2,
"parents_list": [
2,
1
],
"product_count": null,
"subcategories": []
},
{
"id": 6,
"name": "Shirts",
"hashtag": "#womensshirts",
"parent_id": 2,
"parents_list": [
2,
1
],
"product_count": null,
"subcategories": []
},
{
"id": 7,
"name": "Pants and Shorts",
"hashtag": "#womenspantsandshorts",
"parent_id": 2,
"parents_list": [
2,
1
],
"product_count": null,
"subcategories": []
},
{
"id": 8,
"name": "Skirts",
"hashtag": "#skirts",
"parent_id": 2,
"parents_list": [
2,
1
],
"product_count": null,
"subcategories": []
},
{
"id": 9,
"name": "Jeans",
"hashtag": "#womensjeans",
"parent_id": 2,
"parents_list": [
2,
1
],
"product_count": null,
"subcategories": []
},
{
"id": 10,
"name": "Lingerie and Nightweare",
"hashtag": "#lingerieandnightweare",
"parent_id": 2,
"parents_list": [
2,
1
],
"product_count": null,
"subcategories": []
},
{
"id": 12,
"name": "Muslimawear",
"hashtag": "#womensmuslimawear",
"parent_id": 2,
"parents_list": [
2,
1
],
"product_count": null,
"subcategories": []
},
{
"id": 109,
"name": "Other Womensclothes",
"hashtag": "#otherwomensclothes",
"parent_id": 2,
"parents_list": [
2,
1
],
"product_count": null,
"subcategories": []
},
{
"id": 135,
"name": "Sweaters and Jackets",
"hashtag": "#womenssweatersandjackets",
"parent_id": 2,
"parents_list": [
2,
1
],
"product_count": null,
"subcategories": []
}
]
},
{
"id": 15,
"name": "Bags, Purses and Wallets",
"hashtag": "#womensbags",
"parent_id": 1,
"parents_list": [
1
],
"product_count": 1626,
"subcategories": []
},
{
"id": 16,
"name": "Shoes",
"hashtag": "#womensshoes",
"parent_id": 1,
"parents_list": [
1
],
"product_count": 811,
"subcategories": []
},
{
"id": 19,
"name": "Watches",
"hashtag": "#womenswatches",
"parent_id": 1,
"parents_list": [
1
],
"product_count": 513,
"subcategories": []
},
{
"id": 17,
"name": "Eyewear",
"hashtag": "#womenseyewear",
"parent_id": 1,
"parents_list": [
1
],
"product_count": 145,
"subcategories": []
},
{
"id": 18,
"name": "Jewellery",
"hashtag": "#womensjewellery",
"parent_id": 1,
"parents_list": [
1
],
"product_count": 289,
"subcategories": []
},
{
"id": 110,
"name": "Other Womensfashion",
"hashtag": "#otherwomensfashion",
"parent_id": 1,
"parents_list": [
1
],
"product_count": 129,
"subcategories": []
}
]
}
]
}
What I'm thinking I need to do here is declare a function which goes over a tier and returns everything. Like
process_category(category)
{
let html = [];
for(var i = 0; i < category.length; i++)
{
let nested_html = null;
if(i.subcategories.length > 0)
{
nested_html = process_category(i.subcategories);
}
let new_html = [
<ListItem
primaryText={i.name}
onTouchTap={this.click_category.bind(this, i.id)}
nestedItems={[nested_html]}
/>
];
html = [...html, ...new_html];
}
return(html);
}
EDIT:
Feeling incredibly stupud for not realizing how Javascript for/each works (was writing a python for x in categories: print x.name)
The fixed code which works but I'm not sure is optimal:
process_category(category)
{
let html = [];
for(var i in category)
{
let nested_html = null;
if(category[i].subcategories.length > 0)
{
nested_html = this.process_category(category[i].subcategories);
}
let new_html = [
<ListItem
primaryText={category[i].name}
// onTouchTap={this.click_category.bind(this, category[i].id)}
nestedItems={nested_html}
/>
];
html = [...html, ...new_html];
}
return(html);
}
I would recommend recursion:
function generateDom(obj) {
var node = document.createElement("div");
var textnode = document.createTextNode(obj.name);
node.appendChild(textnode);
for (var i in obj.subcategories) {
var subcategory = obj.subcategories[i];
node.append(generateDom(subcategory));
}
return node;
}
Working example: https://jsfiddle.net/mspinks/fdk2m2ua/
Here's a reactjs based fiddle that may get you in the right direction: https://jsfiddle.net/giladaya/yo4xa3z1/4/
Main thing to note is the use of a recursive component:
const Item = function(props) {
let { data } = props
let children
if (data.subcategories.length > 0) {
children = (
<div className={`level-${props.level}`}>
{data.subcategories.map((item, idx) =>
<Item data={item} level={props.level+1} key={`item-${idx}`}/>
)}
</div>
)
} else {
children = null
}
return (
<div>
{data.name}
{children}
</div>
)
}