Home > OS >  How to apply group by on a property of type array using lodash or pure js
How to apply group by on a property of type array using lodash or pure js

Time:10-10

I need to group the data by sub categories, but the property is an array.

I'll appreciate your help, if there is any way to do it with lodash or pure js.

Data Example

const data = [
  { 
     title: "data 1",
     sub_categories:[{ id: 1, name: 'gold'},{ id: 2, name: 'water' }]
  },
  { 
     title: "data 2",
     sub_categories:[{ id: 2, name: 'water'}]
  },
 { 
     title: "data 3",
     sub_categories:[{ id: 1, name: 'gold'},{ id: 3, name: 'fire' }]
  },
 { 
     title: "data 4",
     sub_categories:[] // also can be empty
  }
]

Code Example

 _.chain(data)
  .groupBy(props => ) //need help here
  .map(({values, key}) => {
    return {
      values, 
      key
    }
  })
  .value();

Expected output group by subcategory name (this would be a better solution)

[
  {
    subcategory: "gold",
    list: [{title: "data 1"}, {title: "data: 3"}]
  }
]

CodePudding user response:

You could do this in a couple of steps, which you can combine together with _.flow():

  1. Create a new array by flat mapping sub_categories. This way we 'expand' the array to now include a data object for each subcatgory.
  2. Group the flattened/expanded array by the name of the subcategory
  3. Map the grouped object to your desired format with _.map()

const data = [ { title: "data 1", sub_categories:[{ id: 1, name: 'gold'},{ id: 2, name: 'water' }] }, { title: "data 2", sub_categories:[{ id: 2, name: 'water'}] }, { title: "data 3", sub_categories:[{ id: 1, name: 'gold'},{ id: 3, name: 'fire' }] }, { title: "data 4", sub_categories:[] /* also can be empty */} ];

const grp = _.flow(
  arr => _.flatMap(arr, obj => _.map(obj.sub_categories, ({name}) => ({...obj, name}))),
  flattened => _.groupBy(flattened, 'name'),
  grpd => _.map(grpd, (arr, subcategory) => ({subcategory, list: _.map(arr, ({title}) => ({title}))}))
);

console.log(grp(data));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.21/lodash.min.js" integrity="sha512-WFN04846sdKMIP5LKNphMaWzU7YpMyCU245etK3g/2ARYbPK9Ub18eG ljU96qKRCWh quCY7yefSmlkQw1ANQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

CodePudding user response:

var _ = require('lodash');

const data = [
    { 
       title: "data 1",
       sub_categories:[{ id: 1, name: 'gold'},{ id: 2, name: 'water' }]
    },
    { 
       title: "data 2",
       sub_categories:[{ id: 2, name: 'water'}]
    },
   { 
       title: "data 3",
       sub_categories:[{ id: 1, name: 'gold'},{ id: 3, name: 'fire' }]
    },
   { 
       title: "data 4",
       sub_categories:[] // also can be empty
    }
  ]
  
  g= _.groupBy(data.map(d=>d.sub_categories.map(s=>({"title":d.title, "name":s.name }))).flat(),"name")
  ans=[]
  for (const key in g){
    ans.push({"subcategory":key,"list": g[key].map(v=>({"title":v.title}))})
  }
  console.log(
     ans
  )

You can use above code to get the expected results. groupBy using loadash and other operations done using inbuild functions.

CodePudding user response:

You could group by nested values.

const
    data = [{ title: "data 1", sub_categories: [{ id: 1, name: 'gold' }, { id: 2, name: 'water' }] }, { title: "data 2", sub_categories: [{ id: 2, name: 'water' }] }, { title: "data 3", sub_categories: [{ id: 1, name: 'gold' }, { id: 3, name: 'fire' }] }, { title: "data 4", sub_categories: [] }],
    result = Object.values(data.reduce((r, { title, sub_categories }) => {
        sub_categories.forEach(({ name: subcategory }) => (r[subcategory] ??= { subcategory, list: []}).list.push({ title }));
        return r;
    }, {}));

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

  • Related