Manuel Abascal
Manuel Abascal

Reputation: 6312

Recursively accessing key/value pairs of object within objects & combining them together into a flat array

I have an array of objects that contains all my routes. I need to access all object's nested children properties & their properties and combining the together.

My array of object looks similar to this:

const routes = [
  {
    path: '/system-settings1',
    name: 'global-settings1',
    component: 'tabs1',
    children: [
      {
        path: 'level2-accounting1',
        name: 'local-settings1',
        components: 'modals1',
        children: [
          {
            path: 'level3-accounting1',
            name: 'local-settings1',
            components: 'modals1'
          }
          // more children deeply nested(or not)
        ]
      },
      {
        path: 'level2-accounting1',
        name: 'local-settings1',
        components: 'modals1',
        children: [
          {
            path: 'level3-accounting1',
            name: 'local-settings1',
            components: 'modals1'
          }
          // more children deeply nested(or not)
        ]
      }
    ],
  },
  {
    path: '/system-settings2',
    name: 'global-settings2',
    component: 'tabs2',
    children: [
      {
        path: 'level2-accounting2',
        name: 'local-settings2',
        components: 'modals2',
        children: [
          {
            path: 'level3-accounting2',
            name: 'local-settings2',
            components: 'modals2'
          }
          // more children deeply nested(or not)
        ]
      },
      {
        path: 'level3-accounting2',
        name: 'local-settings2',
        components: 'modals2',
        children: [
          {
            path: 'level4-accounting2',
            name: 'local-settings2',
            components: 'modals2'
          }
          // more children deeply nested(or not)
        ],
      }
    ],
  },
  // more objects with similar key/value pairs
];

I need to make the array of objects into single level array flat like so:

[
  {
    path: '/system-settings1',
    name: 'global-settings1',
    component: 'tabs1',
  },
  {
    path: 'level2-accounting2',
    name: 'local-settings2',
    components: 'modals2',
  },
  {
    path: 'level3-accounting1',
    name: 'local-settings1',
    components: 'modals1'
  },
  {
    path: 'level2-accounting1',
    name: 'local-settings1',
    components: 'modals1',
  }
  // so on if there is more objects etc
]

I have tried to .map() & .filter() combine with a while loop, but to be honest I'm lacking the skills to accomplish by my own & it's not worth to include my attempts. If anybody could assist me with this & explain it would be extremely appreciated.

Upvotes: 0

Views: 261

Answers (2)

Scott Sauyet
Scott Sauyet

Reputation: 50787

Here's a pretty straightforward ES6 function. It is perhaps not the most performant version available, but it's simple.

const flattenAll = (xs) => xs .reduce (
  (all, {children, ...rest}) => [...all, {...rest}, ...flattenAll(children || [])],
  []
)

const routes = [{path: "/system-settings1", name: "global-settings1", component: "tabs1", children: [{path: "level2-accounting1", name: "local-settings1", components: "modals1", children: [{path: "level3-accounting1", name: "local-settings1", components: "modals1"}]}, {path: "level2-accounting1", name: "local-settings1", components: "modals1", children: [{path: "level3-accounting1", name: "local-settings1", components: "modals1"}]}]}, {path: "/system-settings2", name: "global-settings2", component: "tabs2", children: [{path: "level2-accounting2", name: "local-settings2", components: "modals2", children: [{path: "level3-accounting2", name: "local-settings2", components: "modals2"}]}, {path: "level3-accounting2", name: "local-settings2", components: "modals2", children: [{path: "level4-accounting2", name: "local-settings2", components: "modals2"}]}]}];

console .log (flattenAll (routes))

Note that this uses a depth-first ordering; I'm guessing that a breadth-first one would be significantly uglier code, but I haven't tried it.

Upvotes: 1

Andrew Ault
Andrew Ault

Reputation: 579

I tried to edit your code examples so that they made sense and ran without errors. This is a recursive function that gets called on the root routes array, as well as any nested children arrays:

const flatten = routes => {
  const flattened = [];

  for (let i = 0; i < routes.length; i++) {
    const route = routes[i];

    //for each route, grab only the information about the route itself (no children)
    const { path, name, components } = route;
    const flatRoute = { path, name, components };

    //add the new route object to our return array
    flattened.push(flatRoute);

    //if the route had children, recursively call flatten on them
    //and add each child to our return array
    if (route.children) {
      const flatChildren = flatten(route.children);
      flattened.push(...flatChildren);
    }
  }

  return flattened;
};

Upvotes: 1

Related Questions