Home > front end >  How to build a tree from an array of objects on JS?
How to build a tree from an array of objects on JS?

Time:05-03

I have array with data:

const data = [
   { id: 1, type: 'type 1'},
   { id: 2, type: 'type 2', subtype: 'subtype 2'},
   { id: 3, type: 'type 2', subtype: 'subtype 3'},
   { id: 4, type: 'type 2', subtype: 'subtype 4'},
   { id: 5, type: 'type 3', subtype: 'subtype 3'},
]

And I need to build the tree like this:

 type 1
 type 2
   subtype 2
   subtype 3
   subtype 4
 type 3
   subtype 3

CodePudding user response:

In case the OP's example data items keep their simple type/subtype structure the approach boils down to a grouping task where the type's value is the key (property name) of a new group of subtype entries (continuing the object structure) or items (changing to an array structure).

Aggregating (grouped) data at an object is a classic reduce task.

Used language features:

const data = [
   { id: 1, type: 'type 1' },
   { id: 2, type: 'type 2', subtype: 'subtype 2' },
   { id: 3, type: 'type 2', subtype: 'subtype 3' },
   { id: 4, type: 'type 2', subtype: 'subtype 4' },
   { id: 5, type: 'type 3', subtype: 'subtype 3' },
];
console.log(
  data
    .reduce((result, { type, subtype = null }) => {

      const typeGroup = (result[type] ??= {});

      if (subtype !== null) {
        typeGroup[subtype] = {};
      }
      return result;

    }, {})
)
console.log(
  data
    .reduce((result, { type, subtype = null }) => {

      const groupedSubtypeList = (result[type] ??= []);

      if (subtype !== null) {
        groupedSubtypeList.push(subtype);
      }
      return result;

    }, {})
)
console.log(
  Object
    .entries(
      // same reduce functionality as one example before.
      data
        .reduce((result, { type, subtype = null }) => {

          const groupedSubtypeList = (result[type] ??= []);

          if (subtype !== null) {
            groupedSubtypeList.push(subtype);
          }
          return result;

        }, {})
    )
    // additional mapping over the reduce result's entries.
    .map(([type, subtypes]) => {
      const typeItem = {
        type: type.replace('type', '').trim(),
      };
      if (subtypes.length >= 1) {
        typeItem.subtypes = subtypes
          .map(subtype => ({
            subtype: subtype.replace('subtype', '').trim(),
          }));
      }
      return typeItem;
    })
)
.as-console-wrapper { min-height: 100%!important; top: 0; }

CodePudding user response:

Edit 2 - edited for more structured way

const data = [{
    id: 1,
    type: 'type 1'
  },
  {
    id: 2,
    type: 'type 2',
    subtype: 'subtype 2'
  },
  {
    id: 3,
    type: 'type 2',
    subtype: 'subtype 3'
  },
  {
    id: 4,
    type: 'type 2',
    subtype: 'subtype 4'
  },
  {
    id: 5,
    type: 'type 3',
    subtype: 'subtype 3'
  },
];

var pretype = "";
//const newArr = data.map(change);

var pretype = "";
var preindex = -1;
const arr2 = []


data.forEach(function(idx) {
  if (pretype != idx.type) {
    //console.log(idx.type);
    arr2.push({
      //'id': idx.id,
      "type": idx.type.replace("type ", "")
    });

    preindex  ;
  }

  if (idx.subtype) {
    //console.log("pr", preindex, arr2[preindex], arr2[preindex]["subtypes"])
    if (arr2[preindex]["subtypes"] == undefined)
      arr2[preindex]["subtypes"] = [];

    arr2[preindex]["subtypes"].push({
      "subtype": idx.subtype.replace("subtype ", "")
    })
  }
  pretype = idx.type;


});
console.log("arr2: ",arr2)
console.log("flat: ",JSON.stringify(arr2));

function change(id) {
  if (pretype != id.type)
    console.log(id.type);
  if (id.subtype)
    console.log(id.subtype)
  
  pretype = id.type;

}

CodePudding user response:

Build any object from array. Merge the values when you have same keys

const data = [
  { id: 1, type: "type 1" },
  { id: 2, type: "type 2", subtype: "subtype 2" },
  { id: 3, type: "type 2", subtype: "subtype 3" },
  { id: 4, type: "type 2", subtype: "subtype 4" },
  { id: 5, type: "type 3", subtype: "subtype 3" },
];

const buildTreeObj = (arr) => {
  const obj = {};
  arr.forEach((item) => {
    if (obj[item.type]) {
      obj[item.type].subs.push(item.subtype);
    } else {
      obj[item.type] = {
        type: item.type,
        subs: item.subtype ? [item.subtype] : [],
      };
    }
  });
  return Object.values(obj);
};

console.log(buildTreeObj(data));

  • Related