How can I clone a tree structure of an array of objects to another one, changing attributes to the cloned?

650 views Asked by At

How can I clone a tree structure of an array of objects to another one, having different or less attibutes on the cloned one in TypeScript? For example on this:

[
   {
      "name":"root_1",
      "extradata":"whatever",
      "anArray":[
         { "id":1, "value":"test" },
         { "id":1, "value":"test" }
      ],
      "anObject":{ "id":1, "value":"test" },
      "children":[
         {
            "name":"child_1",
            "extradata":"whatever",
            "anArray":[],
            "anObject":{},
            "children":[
               {
                  "name":"root_1",
                  "extradata":"whatever",
                  "anArray":[],
                  "anObject":{},
                  "children":[]
               },
               {
                  "name":"root_1",
                  "extradata":"whatever",
                  "anArray":[],
                  "anObject":{},
                  "children":[]
               }
            ]
         }
      ]
   },
   {
      "name":"root_2",
      "extradata":"whatever",
      "anArray":[],
      "anObject":{},
      "children":[]
   }
]

I need a clone of it but instead of "name" the atribute "label", instad of "extradata" = "key" and without the "anArray" and "anObject". Like this:

[
   {
      "label":"root_1",
      "key":"whatever",
      "children":[
         {
            "label":"child_1",
            "key":"whatever",
            "children":[
               {
                  "label":"root_1",
                  "key":"whatever",
                  "children":[]
               },
               {
                  "label":"root_1",
                  "key":"whatever",
                  "children":[]
               }
            ]
         }
      ]
   },
   {
      "label":"root_2",
      "key":"whatever",
      "children":[]
   }
]

I need to clone it, to use it the data format for the primeng tree component.

I am trying with something like

this.myTree = tree.map((m, index) => Object.assign({}, {
                                label: m.name,
                                key: m.extradata,
                                children: m.children
                            }));

but the children are not following the same shape.

2

There are 2 answers

8
jcalz On BEST ANSWER

I would do this by first defining interfaces for the input and output types in question:

interface InputTree {
  name: string,
  extradata: string,
  anArray: any[],
  anObject: object,
  children: InputTree[]
}

interface OutputTree {
  label: string,
  key: string,
  children: OutputTree[];
}

It looks like your input is an InputTree[] by that definition, and you want to produce an OutputTree[]. Trees are recursive, so you should write a treeMap() function that operates on an InputTree[] and then calls itself recursively on the children of each InputTree in the array. Like this:

const treeMap = (inputTree: InputTree[]): OutputTree[] => inputTree.map(t => ({
  label: t.name,
  key: t.extradata,
  children: treeMap(t.children)
}));

const actual = treeMap(tree);

You can verify that this produces the output you expect:

console.log(JSON.stringify(expected)===JSON.stringify(actual)); // true

Playground link to code

1
CloudBalancing On

I'm not sure if you can use 3rd party libraries - but have you heard of loadsh? There are numerous of examples on how to achieve that (:

first example

second example

If you cannot use it, I would just dive into the code and see how they implemented it (: