Home > Blockchain >  Generate flat array of objects from dynamic nested array
Generate flat array of objects from dynamic nested array

Time:10-20

I have array of objects like below. Here children element may deeply nested, it may contain other children element as well.

let response = [{
  id: 4321,
  name: 'Education',
  parentId: null,
  children: [{
    id: 1234,
    name: 'category1',
    parentId: 4321,
    children: [{
      id: 8327548,
      name: '001',
      parentId: 1234,
    }, {
      id: 8327549,
      name: '002',
      parentId: 1234,
    }],
  }, {
    id: 6786,
    name: 'Associations',
    parentId: 4321,
  }, {
    id: 8262439,
    name: 'category1',
    parentId: 4321,
  }, {
    id: 8245,
    name: 'Rights',
    parentId: 4321,
    children: [{
      id: 2447,
      name: 'Organizations',
      parentId: 8245,
    }, {
      id: 9525,
      name: 'Services',
      parentId: 8245,
    }, {
      id: 8448,
      name: 'Organizations',
      parentId: 8245,
    }],
  }, {
    id: 8262446,
    name: 'Women\'s Rights',
    parentId: 4321,
  }],
}, {
  id: 21610,
  name: 'Agriculture',
  parentId: null,
  children: [{
    id: 3302,
    name: 'categoryABC',
    parentId: 21610,
    children: [{
      id: 85379,
      name: 'categoryABC - General',
      parentId: 3302,
    }, {
      id: 85380,
      name: 'categoryABC Technology',
      parentId: 3302,
    }],
  }, {
    id: 8303,
    name: 'Fungicides',
    parentId: 21610,
    children: [{
      id: 8503,
      name: 'Fungicides - General',
      parentId: 8303,
    }],
  }],
}];

I want to make it flat array of objects but I want to add parent name (which parentId is null) to every objects inside that respective parent.

expected output:

[
  {
      id: 8327548,
      name: "001",
      parentId: 1234
      mainParent: "Education"
  }, {
      id: 8327549,
      name: "002",
      parentId: 1234,
      mainParent: "Agriculture"
  },
  // ...OTHER OBJECTS....
]

What I have done so far

function flat(array) {
  var result = [];
  array.forEach(function (a) {
    result.push(a);
    if (Array.isArray(a.children)) {
      result = result.concat(flat(a.children));
      delete a.children;
    }
  });
  return result;
}

It's giving the flat array of objects but I'm not able to add parent name property to every objects.

Can someone please help me?

CodePudding user response:

You could take a recursive approach an handover the first found name as mainParent.

const
    flat = mainParent => o => o.children
        ? o.children.flatMap(flat(mainParent || o.name))
        : { ...o, mainParent },
    response = [{ id: 4321, name: "Education", parentId: null, children: [{ id: 1234, name: "category1", parentId: 4321, children: [{ id: 8327548, name: "001", parentId: 1234 }, { id: 8327549, name: "002", parentId: 1234 }] }, { id: 6786, name: "Associations", parentId: 4321 }, { id: 8262439, name: "category1", parentId: 4321 }, { id: 8245, name: "Rights", parentId: 4321, children: [{ id: 2447, name: "Organizations", parentId: 8245 }, { id: 9525, name: "Services", parentId: 8245 }, { id: 8448, name: "Organizations", parentId: 8245 }] }, { id: 8262446, name: "Women's Rights", parentId: 4321 }] }, { id: 21610, name: "Agriculture", parentId: null, children: [{ id: 3302, name: "categoryABC", parentId: 21610, children: [{ id: 85379, name: "categoryABC - General", parentId: 3302 }, { id: 85380, name: "categoryABC Technology", parentId: 3302 }] }, { id: 8303, name: "Fungicides", parentId: 21610, children: [{ id: 8503, name: "Fungicides - General", parentId: 8303 }] }] }],
    result = response.flatMap(flat());

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

This is a fairly clean recursion, stopping when there are no children in the node. We capture the first name value found along the hierarchy and carry it through.

const flat = (xs, name = null) => 
  xs .flatMap (x => x .children 
    ? flat (x .children, name || x .name)
    : [{...x, mainParent: name}]
  )

const response = [{id: 4321, name: "Education", parentId: null, children: [{id: 1234, name: "category1", parentId: 4321, children: [{id: 8327548, name: "001", parentId: 1234}, {id: 8327549, name: "002", parentId: 1234}]}, {id: 6786, name: "Associations", parentId: 4321}, {id: 8262439, name: "category1", parentId: 4321}, {id: 8245, name: "Rights", parentId: 4321, children: [{id: 2447, name: "Organizations", parentId: 8245}, {id: 9525, name: "Services", parentId: 8245}, {id: 8448, name: "Organizations", parentId: 8245}]}, {id: 8262446, name: "Women's Rights", parentId: 4321}]}, {id: 21610, name: "Agriculture", parentId: null, children: [{id: 3302, name: "categoryABC", parentId: 21610, children: [{id: 85379, name: "categoryABC - General", parentId: 3302}, {id: 85380, name: "categoryABC Technology", parentId: 3302}]}, {id: 8303, name: "Fungicides", parentId: 21610, children: [{id: 8503, name: "Fungicides - General", parentId: 8303}]}]}]

console .log (flat (response))
.as-console-wrapper {max-height: 100% !important; top: 0}
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

Less obscure, but still fairly concise.

const response = [{ id: 4321, name: 'Education', parentId: null, children: [{ id: 1234, name: 'category1', parentId: 4321, children: [{ id: 8327548, name: '001', parentId: 1234 }, { id: 8327549, name: '002', parentId: 1234 }] }, { id: 6786, name: 'Associations', parentId: 4321 }, { id: 8262439, name: 'category1', parentId: 4321 }, { id: 8245, name: 'Rights', parentId: 4321, children: [{ id: 2447, name: 'Organizations', parentId: 8245 }, { id: 9525, name: 'Services', parentId: 8245 }, { id: 8448, name: 'Organizations', parentId: 8245 }] }, { id: 8262446, name: 'Women\'s Rights', parentId: 4321 }] }, { id: 21610, name: 'Agriculture', parentId: null, children: [{ id: 3302, name: 'categoryABC', parentId: 21610, children: [{ id: 85379, name: 'categoryABC - General', parentId: 3302 }, { id: 85380, name: 'categoryABC Technology', parentId: 3302 }] }, { id: 8303, name: 'Fungicides', parentId: 21610, children: [{ id: 8503, name: 'Fungicides - General', parentId: 8303 }] }] }];

function flatten(arr, mainParent = null) {
  if (!arr) return;

  let result = [];
  for (const obj of arr) {
    result.push(...(flatten(obj.children, mainParent ?? obj.name) ?? [{ ...obj, mainParent }]));
  }

  return result;
}

console.log(flatten(response));
.as-console-wrapper { max-height: 100% !important; top: 0; }
<iframe name="sif3" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

A possible solution could be based entirely on a single, though recursively implemented, reduce task, where the accumulating and recursively passed down object carries both information, the mainParent value and the recursively collected final result ...

function recursivelyReassambleAndCollectChildlessItems(
  { mainParent, result }, { children, ...item }
) {
  result = result.concat(children && children.reduce(

    recursivelyReassambleAndCollectChildlessItems, {
      // was:
      // mainParent: mainParent ?? item.name,
      /**
       *  OP quote:
       *    "... but I want to add parent name 
       *     (which parentId is null) to every
       *     objects inside that respective parent."
       */
      mainParent: item.parentId === null ? item.name : mainParent,
      result: [],
    }
  ).result || { mainParent, ...item });
  
  return { mainParent, result };
}

const response = [{
  id: 4321,
  name: 'Education',
  parentId: null,
  children: [{
    id: 1234,
    name: 'category1',
    parentId: 4321,
    children: [{
      id: 8327548,
      name: '001',
      parentId: 1234,
    }, {
      id: 8327549,
      name: '002',
      parentId: 1234,
    }],
  }, {
    id: 6786,
    name: 'Associations',
    parentId: 4321,
  }, {
    id: 8262439,
    name: 'category1',
    parentId: 4321,
  }, {
    id: 8245,
    name: 'Rights',
    parentId: 4321,
    children: [{
      id: 2447,
      name: 'Organizations',
      parentId: 8245,
    }, {
      id: 9525,
      name: 'Services',
      parentId: 8245,
    }, {
      id: 8448,
      name: 'Organizations',
      parentId: 8245,
    }],
  }, {
    id: 8262446,
    name: 'Women\'s Rights',
    parentId: 4321,
  }],
}, {
  id: 21610,
  name: 'Agriculture',
  parentId: null,
  children: [{
    id: 3302,
    name: 'categoryABC',
    parentId: 21610,
    children: [{
      id: 85379,
      name: 'categoryABC - General',
      parentId: 3302,
    }, {
      id: 85380,
      name: 'categoryABC Technology',
      parentId: 3302,
    }],
  }, {
    id: 8303,
    name: 'Fungicides',
    parentId: 21610,
    children: [{
      id: 8503,
      name: 'Fungicides - General',
      parentId: 8303,
    }],
  }],
}];

console.log(response
  .reduce(recursivelyReassambleAndCollectChildlessItems, { result: [] })
  .result
)
.as-console-wrapper { min-height: 100%!important; top: 0; }
<iframe name="sif4" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related