1

I need to create a nested array of objects from flat array of objects, which has up to 5 levels. The original JSON looks like this:

[{
  "code": "01",
  "name": "Some name 1",
  "level": "1"
}, {
  "code": "01.1",
  "name": "Some name 2",
  "level": "2"
}, {
  "code": "01.11",
  "name": "Some name 3",
  "level": "3"
}, {
  "code": "01.11.1",
  "name": "Some name 4",
  "level": "4"
}, {
  "code": "01.11.11",
  "name": "Some name 5",
  "level": "5"
}, {
  "code": "01.11.12",
  "name": "Some name 6",
  "level": "5"
}]

The new array will be used in Ant Design Tree component, so it should have the following structure:

[
  {
    key: '01',
    title: 'Some name 1',
    children: [
      key: '01.1'
      title: 'Some name 2',
      children: [
        {
          key: '01.11'
          title: 'Some name 3',
          children: [
            {
              key: '01.11.1'
              title: 'Some name 4',
              children: [
                {
                  key: '01.11.11'
                  title: 'Some name 5'
                },
                {
                  key: '01.11.12'
                  title: 'Some name 6'
                }
              ]
            }
          ]
        }
      ]
    ]
  }
]

I have created a function for nesting the array, but the component becomes very slow. I guess there is a better way to do this. Here is my code:

const __getCodes = () => {
  let array = codeData;
  let result = [];
  for(let i = 0; i < array.length; i++) {
    let obj = array[i];
    if (obj.level === "1") {
      result.push({key: obj.code, title: obj.code + ' ' + obj.name, checkable: false});
    }
    if (obj.level === "2") {
      const currentGroup = result.find(group => group.key === obj.code.substring(0,2))
      if (!currentGroup.children) {
        currentGroup.children = []
      }
      currentGroup.children.push({key: obj.code, title: obj.code + ' ' + obj.name, checkable: false})
    }
    if (obj.level === "3") {
      const parentGroup = result.find(group => group.key === obj.code.substring(0,2))
      const currentGroup = parentGroup.children.find(group => group.key === obj.code.substring(0,4))
      if (!currentGroup.children) {
        currentGroup.children = []
      }
      currentGroup.children.push({key: obj.code, title: obj.code + ' ' + obj.name})
    }
    if (obj.level === "4") {
      const subParentGroup = result.find(group => group.key === obj.code.substring(0,2))
      const parentGroup = subParentGroup.children.find(group => group.key === obj.code.substring(0,4))
      const currentGroup = parentGroup.children.find(group => group.key === obj.code.substring(0,5))
      if (!currentGroup.children) {
        currentGroup.children = []
      }
      currentGroup.children.push({key: obj.code, title: obj.code + ' ' + obj.name})
    }
    if (obj.level === "5") {
      const subSubParentGroup = result.find(group => group.key === obj.code.substring(0,2))
      const subParentGroup = subSubParentGroup.children.find(group => group.key === obj.code.substring(0,4))
      const parentGroup = subParentGroup.children.find(group => group.key === obj.code.substring(0,5))
      const currentGroup = parentGroup.children.find(group => group.key === obj.code.substring(0,7))
      if (!currentGroup.children) {
        currentGroup.children = []
      }
      currentGroup.children.push({key: obj.code, title: obj.code + ' ' + obj.name})
    }
  }
  return result;
}

const treeData = __getCodes();

How can I optimize this function to get the desired result?

1 Answer 1

2

You could create a solution that will use level property to push current object at some level in the nested structure and combine that with references and reduce method.

const data = [{"code":"01","name":"Some name 1","level":"1"},{"code":"01.1","name":"Some name 2","level":"2"},{"code":"01.11","name":"Some name 3","level":"3"},{"code":"01.11.1","name":"Some name 4","level":"4"},{"code":"01.11.11","name":"Some name 5","level":"5"},{"code":"01.11.12","name":"Some name 6","level":"5"}]

const result = data.reduce((r, { level, ...rest }) => {
  const value = { ...rest, children: [] }
  r[level] = value.children;
  r[level - 1].push(value)
  return r;
}, [[]]).shift()

console.log(result)

Sign up to request clarification or add additional context in comments.

3 Comments

Thank you very much 🙏 I just changed const value = { key: code, title: name, children: [] } for it to work with antd component. I have a question, how can I add checkable: false to objects at level 1 and 2?
@jupiteror You can just check if the level is < 3 and if so add the property jsfiddle.net/17mreqbk/1
Thank you very much for such an elegant solution! It works great!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.