I want to iterate the tree and need to get the id of all the nodes which has the children in string array. while looping it is just returning me the record but doesn't extract the name of the node.
e.g const result = ['root', 'USER', 'ROLE', 'DASHBOARD', 'BRAND', 'COMPANY'];
{
"id": "root",
"name": "Roles and Permissions",
"children": [
{
"id": "USER",
"name": "USER",
"children": [
{
"id": "1",
"name": "VIEW"
},
{
"id": "2",
"name": "CREATE"
},
{
"id": "3",
"name": "EDIT"
}
]
},
{
"id": "ROLE",
"name": "ROLE",
"children": [
{
"id": "8",
"name": "VIEW"
},
{
"id": "9",
"name": "CREATE"
},
{
"id": "10",
"name": "EDIT"
},
{
"id": "11",
"name": "DELETE"
}
]
},
{
"id": "DASHBOARD",
"name": "DASHBOARD",
"children": [
{
"id": "BRAND",
"name": "BRAND",
"children": [
{
"id": "52",
"name": "VIEW"
},
{
"id": "53",
"name": "CREATE"
},
{
"id": "54",
"name": "EDIT"
},
{
"id": "55",
"name": "DELETE"
}
]
},
{
"id": "COMPANY",
"name": "COMPANY",
"children": [
{
"id": "56",
"name": "VIEW"
},
{
"id": "57",
"name": "CREATE"
},
{
"id": "58",
"name": "EDIT"
},
{
"id": "59",
"name": "DELETE"
}
]
}
]
}
]
}
I tried various looping method to get the list, e.g. but not returning the exact name of the node.
function getParent(nodes) {
if(Array.isArray(nodes.children)) {
return nodes.children.map((node) => getParent(node));
}
return nodes.name;
}
You can store the resp in an array and return that array.
const q = {
"id": "root",
"name": "Roles and Permissions",
"children": [
{
"id": "USER",
"name": "USER",
"children": [
{
"id": "1",
"name": "VIEW"
},
{
"id": "2",
"name": "CREATE"
},
{
"id": "3",
"name": "EDIT"
}
]
},
{
"id": "ROLE",
"name": "ROLE",
"children": [
{
"id": "8",
"name": "VIEW"
},
{
"id": "9",
"name": "CREATE"
},
{
"id": "10",
"name": "EDIT"
},
{
"id": "11",
"name": "DELETE"
}
]
},
{
"id": "DASHBOARD",
"name": "DASHBOARD",
"children": [
{
"id": "BRAND",
"name": "BRAND",
"children": [
{
"id": "52",
"name": "VIEW"
},
{
"id": "53",
"name": "CREATE"
},
{
"id": "54",
"name": "EDIT"
},
{
"id": "55",
"name": "DELETE"
}
]
},
{
"id": "COMPANY",
"name": "COMPANY",
"children": [
{
"id": "56",
"name": "VIEW"
},
{
"id": "57",
"name": "CREATE"
},
{
"id": "58",
"name": "EDIT"
},
{
"id": "59",
"name": "DELETE"
}
]
}
]
}
]
}
let result = []
function r(nodes){
if(Array.isArray(nodes.children)){
result.push(nodes.name);
nodes.children.map((c) => r(c))
return result;
}
return result;
}
console.log(r(q))
You can simply use a recursive function. Here ids is an array. You can initialize it before calling the function. Call this function in your getting IDs method.
const getIdFromNodesWithChild = (node) => {
if (node.children != undefined){
ids.push(node.id)
const children_list = node.children
children_list.forEach( new_child => getIdFromNodesWithChild(new_child))
}}
caller function
const returnIds = (tree) => {
ids = []
getIdFromNodesWithChild(tree)
return (ids)
}
result : ['root', 'USER', 'ROLE', 'DASHBOARD', 'BRAND', 'COMPANY']
Related
Can someone help me regarding my code I already search but had no luck on logic.
i am trying to get a nested drop but i get the same result on 3-child hierarchy.
this is the data from my API.
{
"data": [
{
"id": "1",
"name": "Metro Manila",
"parent": null
},
{
"id": "101",
"name": "Manila",
"parent": "1"
},
{
"id": "10101",
"name": "Malate",
"parent": "101"
},
{
"id": "10102",
"name": "Ermita",
"parent": "101"
},
{
"id": "10103",
"name": "Binondo",
"parent": "101"
},
{
"id": "102",
"name": "Makati",
"parent": "1"
},
{
"id": "10201",
"name": "Poblacion",
"parent": "102"
},
{
"id": "10202",
"name": "Bel-Air",
"parent": "102"
},
{
"id": "10203",
"name": "San Lorenzo",
"parent": "102"
},
{
"id": "10204",
"name": "Urdaneta",
"parent": "102"
},
{
"id": "103",
"name": "Marikina",
"parent": "1"
},
{
"id": "10301",
"name": "Sto Nino",
"parent": "103"
},
{
"id": "10302",
"name": "Malanday",
"parent": "103"
},
{
"id": "10303",
"name": "Concepcion I",
"parent": "103"
},
{
"id": "2",
"name": "CALABARZON",
"parent": null
},
{
"id": "201",
"name": "Laguna",
"parent": "2"
},
{
"id": "20101",
"name": "Calamba",
"parent": "201"
},
{
"id": "20102",
"name": "Sta. Rosa",
"parent": "201"
},
{
"id": "202",
"name": "Cavite",
"parent": "2"
},
{
"id": "20201",
"name": "Kawit",
"parent": "202"
},
{
"id": "203",
"name": "Batangas",
"parent": "2"
},
{
"id": "20301",
"name": "Lipa",
"parent": "203"
},
{
"id": "20302",
"name": "Tanauan",
"parent": "203"
},
{
"id": "3",
"name": "Central Luzon",
"parent": null
},
{
"id": "301",
"name": "Bulacan",
"parent": "3"
},
{
"id": "302",
"name": "Nueva Ecija",
"parent": "3"
},
{
"id": "303",
"name": "Tarlac",
"parent": "3"
},
{
"id": "304",
"name": "Pampanga",
"parent": "3"
}
]
}
this.data = result.body.data;
let parents = this.data.filter(x => x.parent == null);
let child_id = [];
let child_id2 = [];
for (let i = 0; i < parents.length; i++) {
let _myTreelist = new ParentData();
_myTreelist.data.parent = parents[i].name;
child_id = this.data.filter(x => x.parent == parents[i].id); //get child-1 with id
_myTreelist.data.child.child1 = child_id.map((item) => {
return item.name
})
for (let e = 0; e < child_id.length; e++) { //10 ids
child_id2 = this.data.filter(a => a.parent === child_id[e].id); //get child-2 with id
_myTreelist.data.child.child.child2 = child_id2.map((item) => {
return item.name
})
}
this.parentList.push(_myTreelist);
}
this is the image output I get.
it works the first and 2nd nested but in the 3rd it display same
make a recursive function
getChild(element:any,data:any[])
{
element.children=data.filter((x:any)=>x.parent==element.id)
if (element.children.length)
element.children.forEach((x:any)=>this.getChild(x,data))
else
element.children=null;
return element
}
then
treeData=this.data.filter(x=>!x.parent)
.map(x=>this.getChild(x,this.data))
stackblitz
If you use an API and an observable use pipe map
treeData$=this.service.getData().pipe(
map((data:any[])=>{
return data.filter(x=>!x.parent).map(x=>this.getChild(x,data))
})
)
I have below JavaScript with n level children and want to search for id and if any of item from has matching id than need to return object from root to matching item.
I want to return entire hierarchy of found item from root till object with it's children.
I tried with lodash and underscore and could not find easy solution.
input: {
"children": [{
"name": "Home",
"title": "Home",
"id": "home1",
"children": []
},
{
"name": "BUSINESS AND ROLE SPECIFIC",
"title": "BUSINESS AND ROLE SPECIFIC",
"id": "BAR1",
"children": [{
"name": "Global Businesses",
"title": "Global Businesses",
"id": "GB1",
"children": [{
"name": "Commercial Banking",
"title": "Commercial Banking",
"id": "CB1",
"children": [{
"name": "FLAGSHIP PROGRAMMES",
"title": "FLAGSHIP PROGRAMMES",
"id": "FG1",
"children": []
}]
}]
}]
},
{
"name": "RISK MANAGEMENT",
"title": "RISK MANAGEMENT",
"id": "RM1",
"children": []
}
]
}
Search: {
id: 'FG1'
}
return :{
"name": "BUSINESS AND ROLE SPECIFIC",
"title": "BUSINESS AND ROLE SPECIFIC",
"id": "BAR1",
"children": [{
"name": "Global Businesses",
"title": "Global Businesses",
"id": "GB1",
"children": [{
"name": "Commercial Banking",
"title": "Commercial Banking",
"id": "CB1",
"children": [{
"name": "FLAGSHIP PROGRAMMES",
"title": "FLAGSHIP PROGRAMMES",
"id": "FG1",
"children": [{}]
}]
}]
}]
}
You could use this function:
function findChild(obj, condition) {
if (Object.entries(condition).every( ([k,v]) => obj[k] === v )) {
return obj;
}
for (const child of obj.children || []) {
const found = findChild(child, condition);
// If found, then add this node to the ancestors of the result
if (found) return Object.assign({}, obj, { children: [found] });
}
}
// Sample data
var input = { "children": [{ "name": "Home", "title": "Home", "id": "home1", "children": [] }, { "name": "BUSINESS AND ROLE SPECIFIC", "title": "BUSINESS AND ROLE SPECIFIC", "id": "BAR1", "children": [{ "name": "Global Businesses", "title": "Global Businesses", "id": "GB1", "children": [{ "name": "Commercial Banking", "title": "Commercial Banking", "id": "CB1", "children": [{ "name": "FLAGSHIP PROGRAMMES", "title": "FLAGSHIP PROGRAMMES", "id": "FG1", "children": [] }] }] }] }, { "name": "RISK MANAGEMENT", "title": "RISK MANAGEMENT", "id": "RM1", "children": [] } ]},
search = { id: 'FG1' };
console.log(findChild(input, search));
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use this also for searching with multiple conditions, which must be true at the same time:
search = { "name": "Global Businesses", "title": "Global Businesses" };
... would give you the object that has the specified name and title.
Follow-up question
You asked in comments:
Is there way to supply number to not remove children for given node in input. like,
const donotRemoveChildNode = 2;
console.log(findChild(input, search, donotRemoveChildNode ));
...so it will not remove that specific node's children if it matches condition?
Here, if we search for { id: 'FG1'} and supply donotRemoveChildNode = 2, it would not remove the first level children for "Commercial banking".
I would say the donotRemoveChildNode would have to be 3, as there are three levels of children arrays in the ancestor-hierarchy of the "Commercial banking" node. A value of 0 would show the first level children of the top-most children property.
Here is how that extra argument would work -- I added some records to the data to illustrate the difference in the output:
function findChild(obj, condition, removeChildNodesBefore = Infinity) {
if (Object.entries(condition).every( ([k,v]) => obj[k] === v )) {
return obj;
}
for (const child of obj.children || []) {
let found = findChild(child, condition, removeChildNodesBefore - 1);
if (found) {
return Object.assign({}, obj, {
children: removeChildNodesBefore <= 0
? obj.children.map( sibling =>
sibling == child ? found
: Object.assign({}, sibling, {children: []})
)
: [found]
});
}
}
}
var input = { "children": [{ "name": "Home", "title": "Home", "id": "home1", "children": [] }, { "name": "BUSINESS AND ROLE SPECIFIC", "title": "BUSINESS AND ROLE SPECIFIC", "id": "BAR1", "children": [{ "name": "Global Businesses", "title": "Global Businesses", "id": "GB1", "children": [{ "name": "test", "title": "test", "id": "xxx", "children": [{ "name": "testDeep", "title": "test", "id": "deep", "children": []}]}, { "name": "Commercial Banking", "title": "Commercial Banking", "id": "CB1", "children": [{ "name": "test", "title": "test", "id": "yyy", "children": []}, { "name": "FLAGSHIP PROGRAMMES", "title": "FLAGSHIP PROGRAMMES", "id": "FG1", "children": [] }] }] }] }, { "name": "RISK MANAGEMENT", "title": "RISK MANAGEMENT", "id": "RM1", "children": [] } ]},
search = { id: 'FG1' }
console.log(findChild(input, search, 3));
.as-console-wrapper { max-height: 100% !important; top: 0; }
function getBranch(branches, leaf_id)
{
var result_branch = null;
branches.some(function(branch, idx) {
if (branch.id == leaf_id) {
result_branch = Object.assign({}, branch);
result_branch.children.forEach(function(child, idx) {
delete result_branch.children[idx].children;
});
return true;
} else {
let target_branch = getBranch(branch.children, leaf_id);
if (target_branch) {
result_branch = Object.assign({}, branch);
delete result_branch.children
result_branch.children = [target_branch];
return true;
}
}
return false;
});
return result_branch;
}
console.log(getBranch(input.children, 'GB1'));
One way is to first loop the root children, and then create another function to see if the Id exists in any of it's children.
var data = {
"children": [{
"name": "Home",
"title": "Home",
"id": "home1",
"children": []
},
{
"name": "BUSINESS AND ROLE SPECIFIC",
"title": "BUSINESS AND ROLE SPECIFIC",
"id": "BAR1",
"children": [{
"name": "Global Businesses",
"title": "Global Businesses",
"id": "GB1",
"children": [{
"name": "Commercial Banking",
"title": "Commercial Banking",
"id": "CB1",
"children": [{
"name": "FLAGSHIP PROGRAMMES",
"title": "FLAGSHIP PROGRAMMES",
"id": "FG1",
"children": []
}]
}]
}]
},
{
"name": "RISK MANAGEMENT",
"title": "RISK MANAGEMENT",
"id": "RM1",
"children": []
}
]
};
function hasId( id, data ) {
if (data.id === id) return true;
if (data.children) {
for (const child of data.children) {
if (hasId( id, child)) return true;
}
}
return false;
}
function search( id, data ) {
for (const child of data.children) {
if (hasId(id, child)) return child;
}
return null;
}
console.log(search( "FG1", data ));
I have a json array and i need to delete the subarray whose id value is 5, which is falling under the serialNo 1. I tried the following method, but its not deleting any entry in the subarray.
let Details = [
{ "serialNo": "1", "text": "AAA", "subArray": [{ "id": "1", "name": "geo" }, { "id": "5", "name": "gau" }, { "id": "4", "name": "joi" }] },
{ "serialNo": "2", "text": "BBB", "subArray": [{ "id": "7", "name": "rom" }, { "id": "5", "name": "dom" }, { "id": "4", "name": "noi" }] },
{ "serialNo": "3", "text": "CCC", "subArray": [{ "id": "1", "name": "glo" }, { "id": "5", "name": "gum" }, { "id": "4", "name": "lom" }] }
];
Details.map((data) => {
if (data.serialNo === "1") {
data.subArray.map((subDetails) => {
if (subDetails.id === "5") {
delete data.subArray[subDetails];
}
})
}
})
I don't know why you explicitely wants to use the map function. But the following works:
let Details = [
{ "serialNo": "1", "text": "AAA", "subArray": [{ "id": "1", "name": "geo" }, { "id": "5", "name": "gau" }, { "id": "4", "name": "joi" }] },
{ "serialNo": "2", "text": "BBB", "subArray": [{ "id": "7", "name": "rom" }, { "id": "5", "name": "dom" }, { "id": "4", "name": "noi" }] },
{ "serialNo": "3", "text": "CCC", "subArray": [{ "id": "1", "name": "glo" }, { "id": "5", "name": "gum" }, { "id": "4", "name": "lom" }] }
];
Details = Details.map(function (data) {
if (data.serialNo === "1") {
data.subArray = data.subArray.filter(function (sa) {
return (sa.id !== "5");
});
}
return data;
});
console.log(Details);
The first problem is that you're not returning anything from the map functions. The second problem is that data.subArray[subDetails] is undefined, subDetails is an object not an index in the data.subArray array. You can use a combination of map and filter to accomplished this instead of using delete.
let Details = [
{ "serialNo": "1", "text": "AAA", "subArray": [{ "id": "1", "name": "geo" }, { "id": "5", "name": "gau" }, { "id": "4", "name": "joi" }] },
{ "serialNo": "2", "text": "BBB", "subArray": [{ "id": "7", "name": "rom" }, { "id": "5", "name": "dom" }, { "id": "4", "name": "noi" }] },
{ "serialNo": "3", "text": "CCC", "subArray": [{ "id": "1", "name": "glo" }, { "id": "5", "name": "gum" }, { "id": "4", "name": "lom" }] }
];
Details.map((data) => {
if (data.serialNo === "1") {
data.subArray = data.subArray.filter((subDetails) => {
return subDetails.id !== "5";
})
}
return data;
});
console.log(Details);
If you want to stick with map what you need to do is to return undefined when subDetails.id is 5.
let Details = [
{ "serialNo": "1", "text": "AAA", "subArray": [{ "id": "1", "name": "geo" }, { "id": "5", "name": "gau" }, { "id": "4", "name": "joi" }] },
{ "serialNo": "2", "text": "BBB", "subArray": [{ "id": "7", "name": "rom" }, { "id": "5", "name": "dom" }, { "id": "4", "name": "noi" }] },
{ "serialNo": "3", "text": "CCC", "subArray": [{ "id": "1", "name": "glo" }, { "id": "5", "name": "gum" }, { "id": "4", "name": "lom" }] }
];
Details.map((data) => {
if (data.serialNo === "1") {
data.subArray = data.subArray.filter((subDetails) => {
return subDetails.id === "5" ? undefined : subDetails;
})
}
return data;
});
console.log(Details);
One map plus object constructor:
const arr = [
{ "serialNo": "1", "text": "AAA", "subArray": [{ "id": "1", "name": "geo" }, { "id": "5", "name": "gau" }, { "id": "4", "name": "joi" }] },
{ "serialNo": "2", "text": "BBB", "subArray": [{ "id": "7", "name": "rom" }, { "id": "5", "name": "dom" }, { "id": "4", "name": "noi" }] },
{ "serialNo": "3", "text": "CCC", "subArray": [{ "id": "1", "name": "glo" }, { "id": "5", "name": "gum" }, { "id": "4", "name": "lom" }] }
];
const s = 1, id = 5; // conditions
const r = arr.map(e => (e.serialNo == s)
? Object.assign(e, {'subArray': e.subArray.filter(a => a.id != id)})
: e);
console.log(JSON.stringify(r, null, 2));
Object.assign swaps old subArray with the new filtered one.
I'm trying to display a Kendo treeview thanks to a HierarchicalDataSource.
It's a simple region, country, city hierarchy but the difficulty comes with the fact that we have 3 possible levels of regions and countries can appear at the second or at the third level.
Basically,
- First level of regions contains only other regions
- Second level of regions contains other regions or countries
- Third level of regions contains only countries
Here are my schemas:
var portsSchema = {
schema: {
data: "PortList",
model: {
id: "Code"
}
}
};
var countrySchema = {
schema: {
data: "CountryList",
model: {
id: "Code",
children: portsSchema
}
}
};
var regionCountrySchema = {
schema: {
data: "RegionList",
model: {
id: "id",
children: countrySchema
}
}
};
var regionSchema = {
schema: {
data: "RegionList",
model: {
id: "id",
children: regionCountrySchema
}
}
};
Depending on the fact that the region has countries or not, I would like to specify a specific type of children (regionSchema or regionCountrySchema).
var tvDataSource = new kendo.data.HierarchicalDataSource({
data: regions,
schema: {
model: function (data) {
**how to return the right children schema ?**
}
}
});
Returning { children: regionSchema } or {children: regionCountrySchema } triggers a js kendo error.
Any idea to achieve this ? Thank you.
JSON data sample below.
[
{
"Id": 1,
"Name": "MIDDLE EAST AND RED SEA",
"RegionList": [
{
"Id": 12,
"Name": "MIDDLE EAST",
"RegionList": [
{
"Id": 45,
"Name": "M. EAST",
"RegionList": [
],
"CountryList": [
{
"Id": 12007,
"Code": "AE",
"Name": "UAE",
"PortList": [
{
"Id": 6005,
"Code": "AEJEA",
"Name": "JEBEL ALI"
},
{
"Id": 16014,
"Code": "AEAJM",
"Name": "AJMAN"
},
{
"Id": 16015,
"Code": "AEAUH",
"Name": "ABU DHABI"
},
{
"Id": 15109,
"Code": "AEKLF",
"Name": "KHOR AL FAKKAN"
},
{
"Id": 15001,
"Code": "AERKT",
"Name": "RAS AL KHAIMAH"
},
{
"Id": 16018,
"Code": "AESHJ",
"Name": "SHARJAH"
},
{
"Id": 14863,
"Code": "AEQIW",
"Name": "UMM AL QAIWAIN"
},
{
"Id": 15647,
"Code": "AEFJR",
"Name": "AL - FUJAYRAH"
}
]
},
{
"Id": 12018,
"Code": "OM",
"Name": "OMAN",
"PortList": [
{
"Id": 6011,
"Code": "OMSLL",
"Name": "SALALAH"
},
{
"Id": 16218,
"Code": "OMSOH",
"Name": "SOHAR"
}
]
},
{
"Id": 10069,
"Code": "BH",
"Name": "BAHRAIN",
"PortList": [
{
"Id": 15345,
"Code": "BHKBS",
"Name": "BAHRAIN"
}
]
},
{
"Id": 62292,
"Code": "IQ",
"Name": "IRAQ",
"PortList": [
{
"Id": 15383,
"Code": "IQBSR",
"Name": "BASRA"
},
{
"Id": 14673,
"Code": "IQUQR",
"Name": "UMM QASR PT"
}
]
},
{
"Id": 62291,
"Code": "IR",
"Name": "IRAN, ISLAMIC REPUBLIC OF",
"PortList": [
{
"Id": 15250,
"Code": "IRBKM",
"Name": "BANDAR KHOMEINI"
},
{
"Id": 15249,
"Code": "IRBND",
"Name": "BANDAR ABBAS"
},
{
"Id": 14973,
"Code": "IRBUZ",
"Name": "BUSHEHR"
},
{
"Id": 14671,
"Code": "IRKHO",
"Name": "KHORRAMSHAHR"
}
]
},
{
"Id": 62306,
"Code": "KW",
"Name": "KUWAIT",
"PortList": [
{
"Id": 15810,
"Code": "KWSAA",
"Name": "SHUAIBA"
},
{
"Id": 15811,
"Code": "KWSWK",
"Name": "SHUWAIKH"
}
]
},
{
"Id": 12002,
"Code": "SA",
"Name": "SAUDI ARABIA",
"PortList": [
{
"Id": 15039,
"Code": "SAJUB",
"Name": "JUBAIL"
},
{
"Id": 16147,
"Code": "SADMM",
"Name": "AD DAMMAM"
}
]
},
{
"Id": 62364,
"Code": "QA",
"Name": "QATAR",
"PortList": [
{
"Id": 15739,
"Code": "QADOH",
"Name": "DOHA"
},
{
"Id": 14795,
"Code": "QAMES",
"Name": "MESAIEED"
}
]
}
]
}
],
"CountryList": [
]
},
{
"Id": 30,
"Name": "RED SEA",
"RegionList": [
{
"Id": 65,
"Name": "RED SEA",
"RegionList": [
],
"CountryList": [
]
}
],
"CountryList": [
{
"Id": 12002,
"Code": "SA",
"Name": "SAUDI ARABIA",
"PortList": [
{
"Id": 6003,
"Code": "SAKAC",
"Name": "KING ABDULLAH PORT"
},
{
"Id": 15731,
"Code": "SAJED",
"Name": "JEDDAH"
}
]
},
{
"Id": 10114,
"Code": "DJ",
"Name": "DJIBOUTI",
"PortList": [
{
"Id": 8059,
"Code": "DJJIB",
"Name": "DJIBOUTI"
}
]
},
{
"Id": 10122,
"Code": "ER",
"Name": "ERITREA",
"PortList": [
{
"Id": 15031,
"Code": "ERMSW",
"Name": "MASSAWA"
}
]
},
{
"Id": 62300,
"Code": "JO",
"Name": "JORDAN",
"PortList": [
{
"Id": 14801,
"Code": "JOAQJ",
"Name": "AL \u0027AQABAH"
}
]
},
{
"Id": 50001,
"Code": "SD",
"Name": "sd",
"PortList": [
{
"Id": 15734,
"Code": "SDPZU",
"Name": "PORT SUDAN"
}
]
},
{
"Id": 62425,
"Code": "YE",
"Name": "YEMEN",
"PortList": [
{
"Id": 15302,
"Code": "YEHOD",
"Name": "HODEIDAH"
},
{
"Id": 15304,
"Code": "YEMKX",
"Name": "MUKALLA"
},
{
"Id": 15300,
"Code": "YEADE",
"Name": "ADEN"
}
]
},
{
"Id": 10118,
"Code": "EG",
"Name": "EGYPT",
"PortList": [
{
"Id": 16030,
"Code": "EGSOK",
"Name": "SOKHNA PORT"
}
]
}
]
}
],
"CountryList": [
]
}
]
I have following JSON structure:
{
"shops": {
"categories": {
"cat_1": {
"id": "1",
"label": "Men's Fashions",
"Brands": [{
"id": "2",
"name": "Smith"
}]
},
"cat_2": {
"id": "2",
"label": "Restaurants",
"Brands": [{
"id": "3",
"name": "KFC"
}, {
"id": "4",
"name": "SUBWAY"
}, {
"id": "5",
"name": "MLD"
}, {
"id": "6",
"name": "THAI"
}]
},
"cat_3": {
"id": "3",
"label": "Specialty Shops",
"Brands": [{
"id": "7",
"name": "BODY SHOP"
}]
}
}
}
}
I'd like to achieve something like this:
[{
"categoryid": "1",
"id": "2",
"label": "Men's Fashions",
"name": "Smith"
},
{
"categoryid": "2",
"id": "3",
"label": "Restaurants",
"name": "KFC"
},
{
"categoryid": "2",
"id": "4",
"label": "Restaurants",
"name": "SUBWAY"
},
{
"categoryid": "2",
"id": "5",
"label": "Restaurants",
"name": "MLD"
},
{
"categoryid": "2",
"id": "6",
"label": "Restaurants",
"name": "THAI"
}, {
"categoryid": "3",
"id": "7",
"label": "Specialty Shops",
"name": "BODY SHOP"
},
]
Is there an elegant way to achieve it using underscore?
I tried to use nested _.each() to do that, but feel there might be something better.
generateArray: function(obj) {
var newResult = [];
_.each(obj.categories, function(c) {
_.each(c.Brands, function(d) {
newResult.push({
"categoryid": c.id,
"id": d.id,
"label": c.label,
"name": d.name
});
});
});
return newResult;
}
Anyone can advise me which way is more efficiency at running time?
mine or #Artyom Neustroev or #Anthony Chu ?
You don't really need underscore for that task. Use simple for .. in .. and for (...) loops:
var json = {...};
var result = [];
for (var catKey in json.shops.categories) {
var currentCategory = json.shops.categories[catKey];
for (var i = 0; i < currentCategory.Brands.length; i++) {
var currentBrand = currentCategory.Brands[i];
result.push({
categoryid: currentCategory.id,
label: currentCategory.label,
id: currentBrand.id,
name: currentBrand.name
});
}
}
Fiddle here
Instead of each()'s, here's a way to do it with map()'s...
var output = _.chain(input.shops.categories)
.map(function (category) {
return _(category.Brands).map(function (brand) {
return { categoryId: category.id,
id: brand.id,
label: category.label,
name: brand.name
};
});
}).flatten().value();
JSFIDDLE