Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Transform all child objects using recursive reduce in ES6

I'm trying to create a set of reducers in order to change an attribute of all objects in a nested list.

The input payload looks like the following:

const payload = [
  {
    name: "Peter",
    children: [
      {
        name: "Sarah",
        children: [
          {
            name: "Sophie",
            children: [
              {
                name: "Chris"
              }
            ]
          }
        ]
      }
    ]
  }
];

I now want to change the name attribute of all elements and child elements.

const mapJustNickname = elem => {
  return {
    ...elem,
    nickname: elem.name + "y"
  };
};

How do I use this map function recursively on all child elements?

I found a way to do this by putting the the recursion within the same mapping function.

const mapToNickname = (elem) => {
    return {
    nickname: elem.name +'y',
    children: elem.children && elem.children.map(mapToNickname)
  }
}

console.log(payload.map(mapToNickname));

But I'd like to have the mapping of the name separated from the recursion (for reasons of keeping the mapping functions as simple as possible) and being able to chain them later. Is it somehow possible to do this with two reducers and then chaining them together?

like image 965
Kevin Goedecke Avatar asked May 24 '26 21:05

Kevin Goedecke


1 Answers

Create a recursive map function that maps an item, and it's children (if exists). Now you can supply the recursiveMap with a ever transformer function you want, and the transformer doesn't need to handle the recursive nature of the tree.

const recursiveMap = childrenKey => transformer => arr => {
  const inner = (arr = []) =>
    arr.map(({ [childrenKey]: children, ...rest }) => ({
      ...transformer(rest),
      ...children && { [childrenKey]: inner(children) }
    }));
    
  return inner(arr);
};

const mapNickname = recursiveMap('children')(({ name, ...rest }) => ({
  name,
  nickname: `${name}y`,
  ...rest
}));

const payload = [{"name":"Peter","children":[{"name":"Sarah","children":[{"name":"Sophie","children":[{"name":"Chris"}]}]}]}];

const result = mapNickname(payload);

console.log(result)
like image 153
Ori Drori Avatar answered May 27 '26 10:05

Ori Drori