Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write a recursive flat map in javascript?

I have an object of nested route.

Any route MAY contains a list of route childRoutes.

I want to get the list of all the route that contains the key menu.

const routes = [{
        "name": "userManagement",
        "childRoutes": [
          {
            "name": "blogManagement",
            "childRoutes": [
              {
                "name": "blog",  // <=== I want to have this route
                "menu": {
                  "role": 1020
                }
              }
            ],
          },
          {
            "name": "organizationList", // <=== and this one
            "menu": {
              "role": 1004
            }
          }

        ],
      }, { 
      	"name": "test", 
  	"menu": { "role": 4667 }
  	}];

const deepFlatten = arr => [].concat(...arr.map(v => (Array.isArray(v) ? deepFlatten(v) : v)));

// Should handle nesting of route 
const links = deepFlatten(routes).filter((r) => !!r.menu); 

console.log('it should have a length of 3:', links.length === 3);
console.log('it should be blog:', links[0].name === 'blog');
console.log('it should be organizationList:', links[1].name === 'organizationList');
console.log('it should be test:', links[2].name === 'test');

The above snippet does not work recursively yet.

How can I do it recursively without any third-party library ?

like image 217
Dimitri Kopriwa Avatar asked Jan 09 '18 15:01

Dimitri Kopriwa


2 Answers

@yBrodsky's answer can be adapted to isolate and exhibit the generic flatMap operation – here, you'll see that the routes flattened with much of the reduce-map-concat plumbing out of the programmer's way.

// polyfill if you don't have it
Array.prototype.flatMap = function (f)
{
  return this.reduce ((acc, x) =>
    acc.concat (f (x)), [])
}

// your data   
const routes =
    [ { name : "userManagement"
      , childRoutes :
            [ { name : "blogManagement"
              , childRoutes :
                    [ { name : "blog"
                      , menu : { role : 1020 }
                      }
                    ]
              }
            , { name : "organizationList"
              , menu : { role : 1004 }
              }
            ]
      }
    , { name : "test"
      , menu : { role : 4667 }
      }
    ]

// flat-mapped routes
const allChildRoutes =
  routes.flatMap (function loop (node) {
    if (node.childRoutes)
      return node.childRoutes.flatMap (loop)
    else
      return [node]
  })     
  
console.log (allChildRoutes)
like image 147
Mulan Avatar answered Sep 28 '22 10:09

Mulan


how about this, seems to work.

const flatten = (routes) => {
    return routes.reduce((acc, r) => {
      if(r.childRoutes && r.childRoutes.length) {
        acc = acc.concat(flatten(r.childRoutes));
      } else {
        acc.push(r);
      }

      return acc;
    }, [])
}

https://jsfiddle.net/vv9odcxw/

like image 26
yBrodsky Avatar answered Sep 28 '22 12:09

yBrodsky