2

I'm attempting to convert an array that I get in this format:

data = [
    { name: 'Buttons/Large/Primary', id: '1:23' },
    { name: 'Buttons/Large/Secondary', id: '1:24' },
    { name: 'Buttons/Medium/Primary', id: '1:25' },
    { name: 'Buttons/Medium/Secondary', id: '1:26' },
    { name: 'Forms/Text', id: '2:1' },
    { name: 'Forms/Checkbox', id: '2:2' },
];

to an array in this format:

data = [
    {
        name: "Buttons",
        id: '1:23',
        components: [{
            name: "Large",
            id: '1:23',
            components: [{
                name: "Primary",
                id: '1:23'
            }, {
                name: "Secondary",
                id: '1:24'
            }]
        },{
            name: "Medium",
            id: '1:25',
            components: [{
                name: "Primary",
                id: '1:25'
            }, {
                name: "Secondary",
                id: '1:26'
            }]
        }]
    }, {
        name: "Forms",
        id: '2:1',
        components: [{
            name: "Text",
            id: '2:1'
        },{
            name: "Checkbox",
            id: '2:2'
        }]
    }
];

My approach was to create arrays from each object in the original dataset by splitting the name property at '/', then nest them inside each other. This is what I have so far, which nests each item in the original array, but lacks grouping them together like my target format shows. Suggestions?

function nestItems(obj, path, value) {
    let component = {};
    let temp = component;
    for (let i = 0; i < path.length; i++) {
        let component = temp;
        component.name = path[i];
        component.id = value;
        if (path.length - 1 === i) {

        } else {

            component.components = {};
            temp = component.components;
        }
    }
    obj.push(component)
}
let obj = [];
for (let i = 0; i < data.length; i++) {
    let path = data[i].name.split('/');
    nestItems(obj, path, data[i].id);
}
console.log(obj)

1 Answer 1

1

I agree with your approach for splitting with /.

Here's my approach for using reduce to create a map and generating the final array:

const data = [
    { name: 'Buttons/Large/Primary', id: '1:23' },
    { name: 'Buttons/Large/Secondary', id: '1:24' },
    { name: 'Buttons/Medium/Primary', id: '1:25' },
    { name: 'Buttons/Medium/Secondary', id: '1:26' },
    { name: 'Forms/Text', id: '2:1' },
    { name: 'Forms/Checkbox', id: '2:2' },
];

const map = data.reduce((acc, curr) => {
  const { id } = curr;
  const [parent, sub, subSub] = curr.name.split('/');
  if (acc[parent]) {
    if (acc[parent][sub]) {
      acc[parent][sub][subSub] = { id };
    } else {
      acc[parent][sub] = { id };
      if (subSub) {
        acc[parent][sub][subSub] = { id };
      }
    }
  } else {
    acc[parent] = { id };
    if (sub && subSub) {
      acc[parent][sub] = {
        id,
        [subSub]: { id }
      };
    } else if (sub) {
      acc[parent][sub] = { id };
    };
  }
  
  return acc;
}, {});

const result = Object.keys(map).map(parentName => {
  const { id: parentId, ...subs } = map[parentName];
  const parentObj = { name: parentName, id: parentId };
  parentObj.components = Object.keys(subs).map(subName => {
    const { id: subId, ...subSubs } = subs[subName];
    const subObj = { name: subName, id: subId };
    if (Object.keys(subSubs).length) {
      subObj.components = Object.keys(subSubs).map(subSubName => ({ name: subSubName, id: subSubs[subSubName].id }));
    }
    return subObj;
  });
  
  return parentObj;
});

console.log(result);

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

Comments

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.