Search code examples
javascriptreactjsmapreduce

Javascript multi dimensional map and reduce function


I would like to display menu which dynamically changes depends on the user conditions and props which are : if it's root directory, if item is selected or if user have a permission. And here are the menu list object.

const menus = [
      { 'id': 1, 'onHidden': ['root', 'user'] },
      { 'id': 2, 'onHidden': ['root', 'user'] },
      { 'id': 3, 'onHidden': ['user', 'unselected'] },
      { 'id': 4, 'onHidden': ['user', 'unselected'] },
      { 'id': 5, 'onHidden': ['unselected'] },
      { 'id': 6, 'onHidden': ['root', 'user'] },
      { 'id': 7, 'onHidden': ['user', 'unselected'] },
    ]

And on the front end with React, I will pass the conditions to the function as an array object like this:

const shownMenues = pickShownMenus([
      this.props.parent === 0 ? 'root' : false,
      this.props.selected < 0 ? 'unselected' : false,
      this.props.user.permission > 2 ? 'user' : false,
    ])

on pickShownMenus() function tries to return an array of menu.id such as [3, 4, 5, 7] for root directory, [5] for root directory when item is not selected.

question: I've tried to use map and reduce function to get a result but it returns different from that I expected because second iteration of mapping will overwrite everything.... So how can I prevent overwriting and receive a collect result?

Here is the function that I used (not working) :

const pickShownMenus = (props) => {
  const p = props.slice()
  const propsArr = p.filter((x) => x != false)
  const reduce = menus.reduce((arr, menu) => {
    propsArr.map((props) => {
      if (menu.onHidden.indexOf(props) < 0) {
        arr.push(menu.id)
      }
    })
    return arr
  }, [])

  return reduce
}

Solution

  • So, considering have this situation based on what you've provided:

    const menus = [
      { 'id': 1, 'onHidden': ['root', 'user'] },
      { 'id': 2, 'onHidden': ['root', 'user'] },
      { 'id': 3, 'onHidden': ['user', 'unselected'] },
      { 'id': 4, 'onHidden': ['user', 'unselected'] },
      { 'id': 5, 'onHidden': ['unselected'] },
      { 'id': 6, 'onHidden': ['root', 'user'] },
      { 'id': 7, 'onHidden': ['user', 'unselected'] },
    ]
    
    const props = {
      parent: 1,
      selected: -1,
      user: {
        permission: 1
      }
    };
    
    const params = [
      props.parent === 0 ? 'root' : false,
      props.selected < 0 ? 'unselected' : false,
      props.user.permission > 2 ? 'user' : false,
    ]
    

    Based on that, the pickShownMenus should be something like this:

    const pickShownMenus = (params) => {
        const filtered_params = params
            .filter(elm => !!elm) // Remove the falses
        return menus
            .filter(menu => 
              menu.onHidden
                .some(onHiddenDirective => 
                  filtered_params
                    .find(filtered_param => 
                      filtered_param === onHiddenDirective
                    )
                )
            )
            .map(menu => menu.id) // output: [3, 4, 5, 7]
    
      }