How to edit tree structure?

Viewed 145

The tree structure looks like this -

const init = [
    {
        name: 'A',
        children: [
            {
                name: 'A1',
                children: []
            },
            {
                name: 'A2',
                children: [
                    {
                        name: 'A21',
                        children: []
                    }
                ]
            }
        ]
    },
    {
        name: 'B',
        children: [
            {
                name: 'B1',
                children: []
            },
            {
                name: 'B2',
                children: []
            }
        ]
    }
]

And I have variables

  1. currentPath = ['A', 'A2', 'A21']
  2. node = { name: 'A211', children: [] }

I want to transform init to

const init = [
    {
        name: 'A',
        children: [
            {
                name: 'A1',
                children: []
            },
            {
                name: 'A2',
                children: [
                    {
                        name: 'A21',
                        children: [
                            {
                                name: 'A211',
                                children: []
                            }
                        ]
                    }
                ]
            }
        ]
    },
    {
        name: 'B',
        children: [
            {
                name: 'B1',
                children: []
            },
            {
                name: 'B2',
                children: []
            }
        ]
    }
]

Please tell me what is the function that I need to use funcAppendNode(init, currentPath, node) that takes init, the currentPath and the new node and returns the new init. I assume it has something to do with recursion but I am unable to succeed.

Here is what I've tried so far.

const funcAppend = (init, currentPath, node) => {
    let newState = [...init]
    for (let i = 1; i < currentPath.length; i++) {
        newState = newState.find(o => o.name === currentPath[i]).children
    }
    newState.push(node)
    return newState
}

The above function is returning [ { name: 'A211', children: [] } ]

Please help.

3 Answers

const init = [{
    name: 'A',
    children: [{
        name: 'A1',
        children: []
      },
      {
        name: 'A2',
        children: [{
          name: 'A21',
          children: []
        }]
      }
    ]
  },
  {
    name: 'B',
    children: [{
        name: 'B1',
        children: []
      },
      {
        name: 'B2',
        children: []
      }
    ]
  }
];

const currentPath = ['A', 'A2', 'A21'];
const node = {
  name: 'A211',
  children: []
};

let target = {
  children: init
};
currentPath.forEach(path => {
  target = target.children.find(child => child.name === path);
});
target.children.push(node);
console.log(init);
.as-console-wrapper {
  top: 0;
  max-height: 100% !important;
}

I agree with recursion... so first of all, you look for the exit condition... which is path.length = 1. You know exactly what to do in this case.

If the exit condition is not satisfied you should call the function passing a new set of arguments, "reduced".

As similar example to your, I decided to add node to all the paths in items (not only the first one).

appendNode(items, path, node) {
  if (path.length === 1) {
    for (item in items.filter(item => item.name = path[0])) {
      item.children.push(node)
    }   
  } else {
    const firstElement = path.shift(); //removed the first element from path
    for (item in items.filter(item => item.name = firstElement)) {
      addNode(item.children, path, node)
    }
  }
}

I would approach the problem this way:

  1. from your array of names, build your tree path
  2. over the tree path, just append the new node

const toTreePath = ([head, ...tail], data) => {
  const index = data.findIndex((node) => node.name === head);
  const next = data[index]?.children;
  
  return [index, 'children'].concat(
    next?.length ? toTreePath(tail, next) : []
  );
};

const append = (node, path, data) => {
  const $path = toTreePath(path, data);
  
  return R.over(
    R.lensPath($path),
    R.append(node),
    data,
  );
}


// ======

const newNode = 'HELLO WORLD';
const path = ['A', 'A2', 'A21'];

const data = [
  {
    name: 'A',
    children: [
      {
        name: 'A1',
        children: []
      },
      {
        name: 'A2',
        children: [
          {
            name: 'A21',
            children: []
          }
        ]
      }
    ]
  },
  {
    name: 'B',
    children: [
      {
        name: 'B1',
        children: []
      },
      {
        name: 'B2',
        children: []
      }
    ]
  }
];

console.log(
  append(newNode, path, data),
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.js" integrity="sha512-3sdB9mAxNh2MIo6YkY05uY1qjkywAlDfCf5u1cSotv6k9CZUSyHVf4BJSpTYgla+YHLaHG8LUpqV7MHctlYzlw==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

Related