HiveBrain v1.2.0
Get Started
← Back to all entries
snippetjavascriptMinor

Use functional-programming to convert a tree of parent:children objects to array

Submitted by: @import:stackexchange-codereview··
0
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 -

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.