snippetjavascriptMinor
Use functional-programming to convert a tree of parent:children objects to array
Viewed 0 times
childrenobjectsconvertarrayprogrammingparentfunctionalusetree
Problem
Having some trouble with a code I'm trying to refactor, where I need to go over a 'tree' of items, filter some invalid items, and create a new array of filtered items which takes properties from both parent and child objects.
To demo the problem I made a quick snippet -
The code can also be found at here
How would you refactor this code, specifically the 'getValidChildParent' function, in a functional way?
To demo the problem I made a quick snippet -
const items = [
{
name: 'Shirley Hardin',
isValid: true,
children: [
{
name: 'Mildred Mata',
isValid: true,
},
{
name: 'Christopher Herring',
isValid: false,
},
],
},
{
name: 'Tad M. Colbert',
isValid: false,
children: [
{
name: 'James J. Spencer',
isValid: true,
},
],
}
];
function toParentChildModel(parent, child) {
return {
parentName: parent.name,
childName: child.name,
};
}
function getValidChildParent(list) {
const validParentChild = [];
for (let i=0; i<list.length; i++) {
const parent = list[i];
if (parent.isValid) {
for (let j=0; j<parent.children.length; j++) {
const child = parent.children[j];
if (child.isValid) {
validParentChild.push(toParentChildModel(parent, child));
}
}
}
}
return validParentChild;
}
function print(list) {
console.log(list);
}
print(getValidChildParent(items));The code can also be found at here
How would you refactor this code, specifically the 'getValidChildParent' function, in a functional way?
Solution
getValidParentAndChild can be rewritten as follows:function getValidParentAndChild(list){
return list.filter((obj) => obj.isValid)
.map((obj) => obj.children.filter((kid) => kid.isValid)
.map((kid) => toParentChildModel(obj, kid))
.reduce((arr1, arr2) => arr1.concat(arr2));
}The
filter takes the element of the list and keeps it if the condition passed in is met. (In this case, both uses keep all the valid elements.)map applies a function over each element of the list and returns the list of what the function returned for each element. Here it converts the list to a list of the parent-child pairs.reduce is also called fold. These apply a two-argument over a list such that if your list was [a, b, c, d], with the function f, the reduce would return f( f( f(a, b), c), d). Here it is used to make a 2D list a 1D array.This problem becomes more interesting if children could have children. In that case I would do the following:
function getPairsForNode(node){
if(node.children)
return node.children.map((child) => getPairsForNode(child))
.concat(node.children.map((child) => toParentChildModel(node, child))
.reduce((arr1, arr2) => arr1.concat(arr2));
else return [];
}
function getValidParentAndChild(list){
return list.filter((node) => node.isValid)
.map(getPairsForNode)
.reduce((arr1, arr2) => arr1.concat(arr2));
}Code Snippets
function getValidParentAndChild(list){
return list.filter((obj) => obj.isValid)
.map((obj) => obj.children.filter((kid) => kid.isValid)
.map((kid) => toParentChildModel(obj, kid))
.reduce((arr1, arr2) => arr1.concat(arr2));
}function getPairsForNode(node){
if(node.children)
return node.children.map((child) => getPairsForNode(child))
.concat(node.children.map((child) => toParentChildModel(node, child))
.reduce((arr1, arr2) => arr1.concat(arr2));
else return [];
}
function getValidParentAndChild(list){
return list.filter((node) => node.isValid)
.map(getPairsForNode)
.reduce((arr1, arr2) => arr1.concat(arr2));
}Context
StackExchange Code Review Q#135218, answer score: 5
Revisions (0)
No revisions yet.