1

I'm currently working on displaying tables.

But im stuck because the data structure is super nested. This is the original structure:


   {
      "key": "parent_table",
      "title": "parent_table",
      "type": "table",
      "children": [
        {
          "key": "parent_record[0]",
          "title": "parent_record[0]",
          "children": [
            {
              "key": "parent_field_1",
              "title": "parent_field_1",
              "type": "input",
              "children": [
                {
                  "key": "parent_field_1_value",
                  "title": "parent_field_1_value",
                  "value": "2122",
                  "type": "input"
                }
              ]
            },
            {
              "key": "parent_field_2",
              "title": "parent_field_2",
              "type": "table",
              "children": [
                {
                  "key": "children_1_table",
                  "title": "tablerow[1]",
                  "children": [
                    {
                      "key": "column1",
                      "title": "column1",
                      "type": "input",
                      "children": [
                        {
                          "key": "column1_value",
                          "title": "column1_value",
                          "value": "column1_value",
                          "type": "input"
                        }
                      ]
                    },
                    {
                      "key": "column2",
                      "title": "column2",
                      "type": "input",
                      "children": [
                        {
                          "key": "column2_value",
                          "title": "column2_value",
                          "value": "column2_value",
                          "type": "input"
                        }
                      ]
                    }
                  ]
                }
              ]
            }
          ]
        },
        {
          "key": "parent_record[1]",
          "title": "parent_record[1]",
          "children": [
            {
              "key": "parent_field_1",
              "title": "parent_field_1",
              "type": "input",
              "children": [
                {
                  "key": "parent_field_1_value",
                  "title": "parent_field_1_value",
                  "value": "2122",
                  "type": "input"
                }
              ]
            },
            {
              "key": "parent_field_2",
              "title": "parent_field_2",
              "type": "table",
              "children": [
                {
                  "key": "children_2_table",
                  "title": "tablerow[1]",
                  "children": [
                    {
                      "key": "column1",
                      "title": "column1",
                      "type": "input",
                      "children": [
                        {
                          "key": "column1_value",
                          "title": "column1_value",
                          "value": "column1_value",
                          "type": "input"
                        }
                      ]
                    },
                    {
                      "key": "column2",
                      "title": "column2",
                      "type": "input",
                      "children": [
                        {
                          "key": "column2_value",
                          "title": "column2_value",
                          "value": "column2_value",
                          "type": "input"
                        }
                      ]
                    }
                  ]
                }
              ]
            }
          ]
        }
      ]
    }


And this is the expected data structure:

[
  {
    "key": "parent_table",
    "title": "parent_table",
    "type": "table",
    "children": [
      {
        "key": "parent_record[0]",
        "title": "parent_record[0]",
        "children": [
          {
            "key": "parent_field_1",
            "title": "parent_field_1",
            "type": "input",
            "children": [
              {
                "key": "parent_field_1_value",
                "title": "parent_field_1_value",
                "value": "2122",
                "type": "input"
              }
            ]
          }
        ]
      },
      {
        "key": "parent_record[1]",
        "title": "parent_record[1]",
        "children": [
          {
            "key": "parent_field_1",
            "title": "parent_field_1",
            "type": "input",
            "children": [
              {
                "key": "parent_field_1_value",
                "title": "parent_field_1_value",
                "value": "2122",
                "type": "input"
              }
            ]
          }
        ]
      }
    ]
  },
  {
    "key": "parent_field_2",
    "title": "parent_field_2",
    "type": "table",
    "children": [
      {
        "key": "children_1_table",
        "title": "tablerow[1]",
        "children": [
          {
            "key": "column1",
            "title": "column1",
            "type": "input",
            "children": [
              {
                "key": "column1_value",
                "title": "column1_value",
                "value": "column1_value",
                "type": "input"
              }
            ]
          },
          {
            "key": "column2",
            "title": "column2",
            "type": "input",
            "children": [
              {
                "key": "column2_value",
                "title": "column2_value",
                "value": "column2_value",
                "type": "input"
              }
            ]
          }
        ]
      }
    ]
  },
  {
    "key": "parent_field_2",
    "title": "parent_field_2",
    "type": "table",
    "children": [
      {
        "key": "children_2_table",
        "title": "tablerow[1]",
        "children": [
          {
            "key": "column1",
            "title": "column1",
            "type": "input",
            "children": [
              {
                "key": "column1_value",
                "title": "column1_value",
                "value": "column1_value",
                "type": "input"
              }
            ]
          },
          {
            "key": "column2",
            "title": "column2",
            "type": "input",
            "children": [
              {
                "key": "column2_value",
                "title": "column2_value",
                "value": "column2_value",
                "type": "input"
              }
            ]
          }
        ]
      }
    ]
  }
]

Basically the recursive function will pull the children table out from the parent and make the children table same layer with parent table.

5
  • 1
    Does this approach meet your needs? If so I could write up an answer explaining; if not, what am I missing? Commented Feb 27, 2023 at 15:19
  • Hi @jcalz, YES i think this is what im actually looking for! But im still trying to apply it to my code and check whether its working in reactjs side or not. Thank you So much <3 Commented Feb 27, 2023 at 15:26
  • 1
    "But im still trying to apply it to my code and check whether its working in reactjs side or not. " <-- does this mean I should wait until you figure it out? Commented Feb 27, 2023 at 15:27
  • @jcalz yes im still trying to convert it to reactjs so that can test :( but thank you for helping me. I will let you know once I done testing Commented Feb 27, 2023 at 15:53
  • @jcalz YES ITS ACTUALLY WORKING PERFECTLY FINE. Might need your help to explain to me <3 Commented Feb 27, 2023 at 16:02

1 Answer 1

1

For ease of use in TypeScript, let's define the recursive Tree type as follows:

interface Tree {
  key: string;
  title: string;
  value?: string;
  type?: string;
  children?: Tree[]
}

And you want to write a function with the following call signature:

declare function extractTables(tree: Tree): Tree[]

so it takes in a single Tree, and produce an array of Trees corresponding to all the "table"-type tree elements from somewhere in the tree. I assume you don't want to actually mutate the input tree, so we have to make copies of things before we change anything.


The general approach here is: we will walk recursively through the tree doing two things: producing a modified version of the current tree node suitable for appearing in the output, and collecting all the modified table tree nodes from the current subtree. At the end we only need that set of modified table tree nodes, so we will wrap the tree walker with a function that throws away the "current" node at the end.

It looks like this:

function extractTables(tree: Tree) {
  interface WalkResult {
    tables: Tree[],
    modified: Tree
  }
  function walk(tree: Tree): WalkResult {
    const { children, ...base } = tree;
    const tables: Tree[] = [];
    let modifiedChildren: Tree[] | undefined;
    if (children) {
      const walkedChildren = children.map(walk);
      modifiedChildren = walkedChildren
        .filter(wr => wr.modified.type !== "table")
        .map(wr => wr.modified);
      walkedChildren
        .forEach(wr => tables.push(...wr.tables));
    }
    const modified = { ...base, ...children && { children: modifiedChildren } };
    if (modified.type === "table") tables.unshift(modified);
    return { tables, modified };
  }
  return walk(tree).tables;
}

So the inner walk() function is recursive and returns a WalkResult, and extractTables() returns the tables property of walk(tree).

The walk() function itself must take the current node and the WalkResults from running walk on all its children (if they exist), and produce a WalkResult for the current node.

It starts by splitting the current node into its children property and everything else (using destructuring assignment).

If the current node has children, then we recursively walk each child. The current modified node needs a modified children, which we form by collecting each non-"table" modified child. And every set of tables encountered in the children should be concatenated together and used for the tables we return (if there are no children, then this list of tables is empty).

We build up the current modified node by adding back together the non-children properties and the modified children (if it exists). If the current node is a table then we need to prepend it to the list of tables we've built up from the children. And now we have a current modified node and a current list of modified table nodes, so we can return our WalkResult.

So that's it, we're done.


We can check that extractTables(input) for your example input produces the same structure as your example output:

console.log(JSON.stringify(output) === JSON.stringify(expectedOutput)); // true

And it does!

Playground link to code

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.