Home > Net >  Javascript: Efficient way Nested Array mapping & filtering to get the desired results
Javascript: Efficient way Nested Array mapping & filtering to get the desired results

Time:02-16

I have tried the below solution for question2 to get result2. What would be a more efficient way to get both the result (result1, result2 & result3) with the same code?

question1 = [
  {
    "groupName": "Group 1",
    "id": "group1",
    "options": [
      {
        "name": "Cat1",
        "selected": true
      },
      {
        "name": "Cat2",
        "selected": true
      },
      {
        "name": "Cat3",
        "selected": false
      },
      {
        "name": "Cat4",
        "selected": false
      }
    ]
  },
  {
    "groupName": "Group 2",
    "id": "Brand",
    "options": [
      {
        "name": "brand1",
        "selected": false
      },
      {
        "name": "brand2",
        "selected": true
      },
      {
        "name": "brand3",
        "selected": false
      }
    ]
  },
  {
    "groupName": "Group 3",
    "id": "Price",
    "options": [
      {
        "name": "$0 - $9",
        "selected": false
      },
      {
        "name": "$9 - $19",
        "selected": false
      },
      {
        "name": "$20 - $29",
        "selected": false
      }
    ],
    "range": {
      "min": 5,
      "max": 20
    }
  }
]

result1 = [{
    "groupName": "Group 1",
    "id": "group1",
    "name": "Cat1",
  },
  {
    "groupName": "Group 1",
    "id": "group1",
    "name": "Cat2",
  },
  {
    "groupName": "Group 2",
    "id": "Brand",
    "name": "brand2",
  },
  {
    "groupName": "Group 3",
    "id": "Price",
    "min": 5,
    "max": 20
  }
]

I have a solution for question2, although I know it's not very efficient, so what could be a better solution?

question2 = [
  {
    "groupName": "Group 1",
    "id": "group1",
    "options": [
      {
        "name": "Cat1",
        "selected": true
      },
      {
        "name": "Cat2",
        "selected": false
      },
      {
        "name": "Cat3",
        "selected": false
      },
      {
        "name": "Cat4",
        "selected": false
      }
    ]
  },
  {
    "groupName": "Group 2",
    "id": "Brand",
    "options": [
      {
        "name": "brand1",
        "selected": false
      },
      {
        "name": "brand2",
        "selected": true
      },
      {
        "name": "brand3",
        "selected": false
      }
    ]
  },
  {
    "groupName": "Group 3",
    "id": "Price",
    "options": [
      {
        "name": "$0 - $9",
        "selected": true
      },
      {
        "name": "$9 - $19",
        "selected": false
      },
      {
        "name": "$20 - $29",
        "selected": false
      }
    ],
    "range": {
      "min": null,
      "max": null
    }
  }
]


const selected2 = question2.map(group => group.options.filter(option => option.selected).map(option => ({groupName: group.groupName, id: group.id, name: option.name}))).flat(1)


console.log(selected2)

For question3, group 1, none of the options is selected and correspondingly I should get result3. So, only if any of the options are selected or the price has a range (either min/max/both min&max), it is displayed in the result.

question3 = [
  {
    "groupName": "Group 1",
    "id": "group1",
    "options": [
      {
        "name": "Cat1",
        "selected": false
      },
      {
        "name": "Cat2",
        "selected": false
      },
      {
        "name": "Cat3",
        "selected": false
      },
      {
        "name": "Cat4",
        "selected": false
      }
    ]
  },
  {
    "groupName": "Group 2",
    "id": "Brand",
    "options": [
      {
        "name": "brand1",
        "selected": false
      },
      {
        "name": "brand2",
        "selected": true
      },
      {
        "name": "brand3",
        "selected": false
      }
    ]
  },
  {
    "groupName": "Group 3",
    "id": "Price",
    "options": [
      {
        "name": "$0 - $9",
        "selected": false
      },
      {
        "name": "$9 - $19",
        "selected": false
      },
      {
        "name": "$20 - $29",
        "selected": false
      }
    ],
    "range": {
      "min": 5,
      "max": 20
    }
  }
]

result3 = [
  {
    "groupName": "Group 2",
    "id": "Brand",
    "name": "brand2",
  },
  {
    "groupName": "Group 3",
    "id": "Price",
    "min": 5,
    "max": 20
  }
]

I want to use reduce to get these above (result1, result2 & result3) solutions. Could someone help me with this?

Edited to check scenario where two are selected in the same group, solution resulting in result1.

CodePudding user response:

When multiple selected trues found in the accumulator object I'm adding a key where keyname is a combination of groupName and selected name. If no selected true but has max or min values the key name will be just groupName. I take Object.values() of the final object to get the array of values.

const question1 = [{"groupName": "Group 1","id": "group1","options": [{"name": "Cat1","selected": true},{"name": "Cat2","selected": true},{"name": "Cat3","selected": false},{"name": "Cat4","selected": false}]},{"groupName": "Group 2","id": "Brand","options": [{"name": "brand1","selected": false},{"name": "brand2","selected": true},{"name": "brand3","selected": false}]},{"groupName": "Group 3","id": "Price","options": [{"name": "$0 - $9","selected": false},{"name": "$9 - $19","selected": false},{"name": "$20 - $29","selected": false}],"range": {"min": 5,"max": 20}}]

const question2 = [{"groupName": "Group 1","id": "group1","options":[{"name":"Cat1","selected": true},{"name": "Cat2","selected": false},{"name":"Cat3","selected": false},{"name": "Cat4","selected": false}]},{"groupName": "Group 2","id": "Brand","options": [{"name":"brand1","selected":false},{"name": "brand2","selected": true},{"name": "brand3","selected": false}]},{"groupName": "Group 3","id": "Price","options": [{"name": "$0 -$9","selected": true},{"name": "$9 - $19","selected": false},{"name": "$20 -$29","selected": false}],"range": {"min": null,"max": null}}]

const question3 = [{"groupName": "Group 1","id": "group1","options": [{"name": "Cat1","selected": false},{"name": "Cat2","selected": false},{"name": "Cat3","selected": false},{"name": "Cat4","selected": false}]},{"groupName": "Group 2","id": "Brand","options": [{"name": "brand1","selected": false},{"name": "brand2","selected": true},{"name": "brand3","selected": false}]},{"groupName": "Group 3","id": "Price","options": [{"name": "$0 - $9","selected": false},{"name": "$9 - $19","selected": false},{"name": "$20 - $29","selected": false}],"range": {"min": 5,"max": 20}}]


const formatter = (arr) => {
    return Object.values(arr.reduce((acc,curr) => {
    
    const hasMax = curr.range && curr.range.max;
    const hasMin = curr.range && curr.range.max
    const filtered = curr['options'].filter((option) => option.selected);
    
    if (filtered.length) {
        filtered.forEach((el) => {
        acc[curr.groupName el.name] = {id: curr.id,groupName: curr.groupName,name: el.name}
      })
    }
    else if (hasMin || hasMax){
        acc[curr.groupName] = {id: curr.id,groupName: curr.groupName}
      if(hasMax) acc[curr.groupName]['max'] = curr.range.max
      if(hasMin) acc[curr.groupName]['min'] = curr.range.min
    }
  return acc;
},{}))
}

const result1 = formatter(question1)
const result2 = formatter(question2)
const result3 = formatter(question3)

console.log(result1)
console.log(result2)
console.log(result3)
.as-console-wrapper { max-height: 100% !important; top: 0; }

  • Related