How to map the values of all the leaf nodes in Javascript? - javascript

I have a nested JSON object tree like this :
{"children":[{"name":"Afghanistan","children":[{"World
Cities.Country":"Afghanistan","World Cities.Population":2997,"World
Cities.City":"Qal eh-ye Now"},{"World Cities.Country":"Afghanistan","World
Cities.Population":7407,"World Cities.City":"Mahmud-E Eraqi"},{"World
Cities.Country":"Afghanistan","World Cities.Population":10000,"World
Cities.City":"Tarin Kowt"}]
EXPECTED OUTPUT IS SOMETHING LIKE THIS
{
"name": "flare",
"children": [
{
"name": "LEGISLATIVE",
"children": [
{
"name": "Legislative Branch",
"size": 20891
}
]
},
{
"name": "JUDICIAL",
"children": [
{
"name": "Supreme Court Law Library",
"size": 1589.3
},
{
"name": "New Mexico Compilation Commission",
"size": 1853.5
},
{
"name": "Judicial Standards Commission",
"size": 860.8
},
{
"name": "Court of Appeals",
"size": 5960.2
},
{
"name": "Supreme Court",
"size": 3421.1
},
{
"name": "Supreme Court Building Commission",
"size": 977.4
},
{
"name": "Administrative Office of the Courts",
"size": 65870.4
},
{
"name": "First Judicial District Court",
"size": 8372.5
},
{
"name": "Second Judicial District Court",
"size": 28154.6
},
{
"name": "Third Judicial District Court",
"size": 7808.3
},
{
"name": "Fourth Judicial District Court",
"size": 2577.2
},
{
"name": "Fifth Judicial District Court",
"size": 7389.5
},
{
"name": "Sixth Judicial District Court",
"size": 3630.7
},
{
"name": "Seventh Judicial District Court",
"size": 2895
},
Expected output for my example :
{"children":[{"name":"Afghanistan","children":[{"name":"Qal eh-ye Now","value":2997}]]}
So I want to map the values of the leaf nodes. In this example ,World Cities.Country,World Cities.Population and World Cities .City to just a name and value for every children object.
Currently this is the function that I have :
var mappedData = nestedData.children.map(function (d) {
return { name: d[groupKey], value: d[sizeKey] };
}); //groupKey is World.Cities.City ,sizeKey is Population
But obviously this syntax does not work because I first need to access all the leaf nodes of this tree then apply the map function to it. How can I achieve that?

This is how you can achieve that:
const a = {
children: [
{
name: "Afghanistan",
children: [
{
"World Cities.Country": "Afghanistan",
"World Cities.Population": 2997,
"World Cities.City": "Qal eh-ye Now"
},
{
"World Cities.Country": "Afghanistan",
"World Cities.Population": 7407,
"World Cities.City": "Mahmud-E Eraqi"
},
{
"World Cities.Country": "Afghanistan",
"World Cities.Population": 10000,
"World Cities.City": "Tarin Kowt"
}
]
}
]
};
const deep = x => {
if (Array.isArray(x.children)) {
x.children = x.children.map(deep);
return x;
} else {
return {
name: x["World Cities.City"],
value: x["World Cities.Population"]
};
}
};
const b = deep(a);
console.log(b);

Related

How can i group and restructure the JSON object in Angular8

I am getting below response, I want to ReGroup all the data and its children based on buSubRegion which is present inside children now. And also needs to add buSubRegion outside children.
For EX - In below Response, 1UL Africa belongs to Africa object and also present inside Europe object, so i need to merge children of all objects which belongs to 1UL Africa into one array of object.
I want if buSubRegion have a same value and it is present inside many objects then find all those objects and merge into one.
Also, Agbara - Savoury dont have a BU sub-region So i don't want to include this object.
Can anyone please help me to achieve this.
const data = [
{
"name": "Africa",
"id":1,
"children": [
{
"name": "Agbara - Laundry",
"buSubRegion": "1UL Africa",
"children": [
{
'lineId':"R_D005_TPKDST02"
}
]
},
{
"name": "Agbara - Savoury",
"children": [
{
"lineId":"R_D005_TPKDST02"
}
]
}
]
},
{
"name": "Europe",
"id":2,
"children": [
{
"name": "Europe1",
"buSubRegion": "1UL Africa",
"children": [
{
"lineId":"R_D005_TPKDST02"
}
]
},
{
"name": "Europe2",
"buSubRegion": "Test Europe",
"children": [
{
"lineId":"R_D005_TPKDST02"
}
]
}
]
},
{
"name": "Latem",
"id":3,
"children": [
{
"name": "test1",
"buSubRegion": "latem1",
"children": [
{
"lineId":"R_D005_TPKDST02"
}
]
}
]
}
];
Below is my Expected Output
[
{
"buSubRegion": "1UL Africa",
"name": "Africa",
"id":1,
"children": [
{
"name": "Agbara - Laundry",
"buSubRegion": "1UL Africa",
"children": [
{
"lineId":"R_D005_TPKDST02"
}
]
},
{
"name": "Europe1",
"buSubRegion": "1UL Africa",
"children": [
{
"lineId":"R_D005_TPKDST02"
}
]
}
]
},
{
"buSubRegion": "Test Europe",
"name": "Europe",
"id":2,
"children": [
{
"name": "Europe2",
"buSubRegion": "Test Europe",
"children": [
{
"lineId":"R_D005_TPKDST02"
}
]
}
]
},
{
"name": "Latem",
"buSubRegion": "latem1",
"id":3,
"children": [
{
"name": "test1",
"buSubRegion": "latem1",
"children": [
{
"lineId":"R_D005_TPKDST02"
}
]
}
]
}
];
You can make use of reduce and inside that loop through children property to group the data by buSubRegion.
const data = [{"name":"Africa","id":1,"children":[{"name":"Agbara - Laundry","buSubRegion":"1UL Africa","children":[{"lineId":"R_D005_TPKDST02"}]},{"name":"Agbara - Savoury","children":[{"lineId":"R_D005_TPKDST02"}]}]},{"name":"Europe","id":2,"children":[{"name":"Europe1","buSubRegion":"1UL Africa","children":[{"lineId":"R_D005_TPKDST02"}]},{"name":"Europe2","buSubRegion":"Test Europe","children":[{"lineId":"R_D005_TPKDST02"}]}]},{"name":"Latem","id":3,"children":[{"name":"test1","buSubRegion":"latem1","children":[{"lineId":"R_D005_TPKDST02"}]}]}];
const result = data.reduce((a,{children, ...rest})=>{
children.forEach(({buSubRegion,...others})=>{
if(buSubRegion){
a[buSubRegion] ??= {buSubRegion, ...rest, children:[]};
a[buSubRegion].children.push({buSubRegion, ...others})
}
});
return a;
},{});
console.log(Object.values(result));

How to filter nested JSON children objects and return result Angular 8

I am getting API response inside filterchildrenByRegion() function,
I want to remove those object which are not matching with the selected Region and return all data as it is.
Ex 1 -
If i will pass '1UL Africa' inside changeRegion() function,than it will return data as my expected output 1.
Ex - 2 - If i will pass 'South Africa"' inside changeRegion() function,than it will return data as my expected output 2.
changeRegion(){
this.newRegion = this.filterchildrenByRegion('1UL Africa');
}
filterchildrenByRegion(region){
this.data = [
{
"name": "Africa",
"children": [
{
"name": "Test1",
"region": "1UL Africa"
},
{
"name": "Test2",
"region": "South Africa",
},
{
"name": "Test3",
"region": "New Test",
}
]
},
{
"name": "Europe",
"children": [
{
"name": "Test4",
"region": "1UL Africa"
},
{
"name": "Test5",
"region": "Test Europe"
}
]
}
];
return this.data.filter(x => x.children.map(child => child.region).includes(regionName));
};
Expected OutPut1
result = this.data = [
{
"name": "Africa",
"children": [
{
"name": "Test1",
"region": "1UL Africa"
}
]
},
{
"name": "Europe",
"children": [
{
"name": "Test4",
"region": "1UL Africa"
}
]
}
];
Expected OutPut 2
result = this.data = [
{
"name": "Africa",
"children": [
{
"name": "Test1",
"region": "1UL Africa"
}
]
}
];
Here is a sample that will work for your case
return this.data.map((x) => {
const childrenFulfillingTheSearch = x.children.filter(c => c.region.includes(region));
if (childrenFulfillingTheSearch.length === 0) {
return undefined; //this country has no children fulfilling the requirements
}
return {
...x,
children: childrenFulfillingTheSearch
};
})
.filter(x => x !== undefined);
Click here to view a running example

Grouping a multilevel array of objects

I am trying to learn javascript reduce and map an I came across some difficulties.
I have an array with the following format. The id of the parent is same as the location_id of the child. I need to group the array into a nested format.
arr = [
{
"id": 4583211,
"name": "Location 1",
"location_id": null,
},
{
"id": 7458894,
"name": "Location 12",
"location_id": 4583211
},
{
"id": 7463953,
"name": "Location 13",
"location_id": 4583211
},
{
"id": 80302210,
"name": "Location 121",
"location_id": 7458894
},
{
"id": 80302219,
"name": "Location 122",
"location_id": 7458894
},
{
"id": 7464314,
"name": "Location 131",
"location_id": 7463953
},
{
"id": 4583216,
"name": "Location 2",
"location_id": null,
},
{
"id": 3566353,
"name": "Location 21",
"location_id": 4583216
},
]
This array should be grouped as:
result = [
{
"id": 4583211,
"name": "Location 1",
"locations": [
{
"id": 7458894,
"name": "Location 12",
"locations": [
{
"id": 80302210,
"name": "Location 121"
},
{
"id": 80302219,
"name": "Location 122"
}
]
},
{
"id": 7463953,
"name": "Location 13",
"locations": [
{
"id": 7464314,
"name": "Location 131"
}
]
}
]
},
{
"id": 4583216,
"name": "Location 2",
"locations": [
{
"id": 3566353,
"name": "Location 21"
}
]
}
]
I tried to group it using the following method found on SO but it gives different result.
result = arr.reduce(function (r, a) {
r[a.location_id] = r[a.location_id] || [];
r[a.location_id].push(a);
return r;
}, Object.create(null));
You could do this using reduce and recursion you just need to check if parent is equal to current elements location_id.
const data = [{"id":4583211,"name":"Location 1","location_id":null},{"id":7458894,"name":"Location 12","location_id":4583211},{"id":7463953,"name":"Location 13","location_id":4583211},{"id":80302210,"name":"Location 121","location_id":7458894},{"id":80302219,"name":"Location 122","location_id":7458894},{"id":7464314,"name":"Location 131","location_id":7463953},{"id":4583216,"name":"Location 2","location_id":null},{"id":3566353,"name":"Location 21","location_id":4583216}]
function create(data, parent = null) {
return data.reduce((r, e) => {
if(parent == e.location_id) {
const o = { id: e.id, name: e.name }
const children = create(data, e.id);
if(children.length) o.locations = children;
r.push(o)
}
return r
}, [])
}
console.log(create(data))

Functional approach to transform an array of objects into a hierarchical structure with aggregates

I'm looking for a functional solution to map this object into a hierarchical structure and group by practice, subjectarea, and asset so that this object:
var data = {
"research": [
{ "practice": "Talent Management", "id": "20992", "title": "Creating a Culture of Leadership", "subjectArea": "Talent Strategy" },
{ "practice": "Talent Management", "id": "20993", "title": "Talent Economics", "subjectArea": "Talent Strategy" },
{ "practice": "Talent Management", "id": "20990", "title": "Finding the Right Talent", "subjectArea": "Recruiting" },
{ "practice": "Human Resources", "id": "20994", "title": "Tips from the Front", "subjectArea": "HR Training" },
{ "practice": "Human Resources", "id": "20995", "title": "Reward Programs", "subjectArea": "Employee Engagement" },
]
}
gets transformed into this (count the number of items for a practice and add the subject areas for the practice as children, count the number of items for a subject area within the practice and add the asset (id and title) as children for the subject area):
{
"name": "research",
"children": [
{
"name": "Talent Management", "size": 3, "children": [
{
"name": "Talent Strategy", "size": 2, "children": [
{ "name": "Creating a Culture of Leadership", "id": "20992", "size": 1 },
{ "name": "Talent Economics", "id": "20993", "size": 1 }
]
},
{
"name": "Recruiting", "size": 1, "children": [
{ "title": "Finding the Right Talent", "id": "20990", "size": 1 },
]
}
]
},
{
"name": "Human Resources", "size": 2, "children": [
{
"name": "HR Training", "size": 1, "children": [
{ "name": "Tips from the Front", "id": "20994", "size": 1 },
]
},
{
"name": "Employee Engagement", "size": 1, "children": [
{ "name": "Reward Programs", "id": "20995", "size": 1 },
]
}
]
},
]
}
I haven't been able to sort out the map and reduce combination to use to yield the correct result with counts, and appreciate any insight.
It might not be what SO is for (as per comments above), but in case anyone needs to transform an array of flat objects into a hierarchical structure that you can simply specify the nesting order, number of levels, and field names, here is a recursive function to do so - https://github.com/lance-p/configurable-transform-flat-array-to-nested. Hope it might be of help to others.

Delete item from Array with nested items

I need to delete item from an array with nested items. Here's the array,
{
"name": "Main Course",
"items": [
{
"menuname": "Chinese",
"id": "12",
"menu": [
{"name": "Noodles",id="1"},
{"name": "Rice",id="2"},
{"name": "Xinjiang Roast",id="3"}
]
},
{
"menuname": "Indian",
"id": "14",
"menu": [
{"name": "Rice",id="2"},
{"name": "Paratha",id="5"},
{"name": "Dal Fry",id="6"}
]
}
]
}
I need to delete the item say, {"name": "Rice",id="2"}, from the first menu (menuname:Chinese). Please note that the same item appears in another menu (menuname:Indian) too, which I don't want to delete. Looks like the common approach is to find the indexOf the item to delete and splice it. Here's what I tried,
myArray[0].items.forEach(function (val) {
if((val.menuname==="Chinese" && val.id==="12"))
{
val.menu.forEach(function (value) {
if(value.name === "Rice" && value.id==="2"){
myArray.indexOf(value.name);
}
})
}
});
This always returns an index of -1. What am I doing wrong?
Edit:A close vote for unclear question (Seriously?). The code I am using doesn't return the proper index and I asked what is wrong with the code. With all due respect, please spend some time reading the question.
First your JSON string look strange.
Then you can't call myArray[0] because you don't get an array:
var k = {
"name": "Main Course",
"items": [{
"menuname": "Chinese",
"id": "12",
"menu": [{
"name": "Noodles",
"id": "1"
}, {
"name": "Rice",
"id": "2"
}, {
"name": "Xinjiang Roast",
"id": "3"
}]
}, {
"menuname": "Indian",
"id": "14",
"menu": [{
"name": "Rice",
"id": "2"
}, {
"name": "Paratha",
"id": "5"
}, {
"name": "Dal Fry",
"id": "6"
}]
}]
};
k.items.forEach(function (val) {
if (val.menuname === "Chinese" && val.id === "12") {
for (var i = 0; i < val.menu.length; i++) {
if (val.menu[i].name === "Rice" && val.menu[i].id === "2") {
val.menu.splice(i, 1);
}
}
}
});
console.log(k);
http://jsfiddle.net/XmsQR/2/

Categories

Resources