Home > Mobile >  Using Lodash countBy for nested objects
Using Lodash countBy for nested objects

Time:11-15

I have some json, example below:

[
 {
  "category": {
   "name": "Technology",
   "key": "012"
  }
 },
 {
  "category": {
   "name": "Kitchen",
   "key": "016"
  }
 },
 {
  "category": {
   "name": "Technology",
   "key": "012"
  }
 }
]

I want to count the occurrences from the data and map them to create a list in a react component. I want to display, the name, key and occurrences they appear in the list. And I want to display only 1 instance of the item with its occurrences in the list. I want to use Lodash to achieve this.

// Example 1 - Lists each category with the correct values. eg. Technology(012,2), Kitchen(016,1), Technology(012,2).
const categories = items.map( item => item.category )
const countCategories = countBy(categories)

// React Component
{ Object.keys(categories).map(category =>
 <CustomComponent category={category.name} key={category.key} count={countCategories[category.name]} />
// Example 2 - Lists only one instance of each unique category by name with the count but not the key. eg. Technology(,2), Kitchen(,1)
const categories = items.map( item => item.category.name )
const countCategories = countBy(categories)

// React Component
{ Object.keys(countCategories).map(category =>
 <CustomComponent category={category} key={'NA'} count={countCategories[category]} />
)}

The desired outcome I'm looking for, is to list only one instance of each category in the list, with the name, count and key. It seems I can only count the occurrences of .name or .key which in turn means I can't include the other in my map. How can I achieve this using Lodash?

CodePudding user response:

With lodash you can use _.groupBy() to batch items by category.name, and then map the groups, and create an array of categories with the count:

const arr = [
 { "category": { "name": "Technology", "key": "012" } },
 { "category": { "name": "Kitchen", "key": "016" } },
 { "category": { "name": "Technology", "key": "012" } }
];

const result = _.map(
  _.groupBy(arr, 'category.name'),
 items => ({
  ...items[0].category,
  count: items.length
 })
)

console.log(result);
<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>
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

CodePudding user response:

Using Array#reduce, iterate over the list while updating a Map where the key is the category name and the value is the category with the updated count.

The result would be the final values of the Map which are the categories grouped by the name, each with the final count:

const arr = [
 { "category": { "name": "Technology", "key": "012" } },
 { "category": { "name": "Kitchen", "key": "016" } },
 { "category": { "name": "Technology", "key": "012" } }
];

const res = [...
  arr.reduce((categoryMap, { category }) => {
    if(categoryMap.has(category.name)) {
      categoryMap.get(category.name).count  ;
    } else {
      categoryMap.set(category.name, {...category, count: 1});
    }
    return categoryMap;
  }, new Map)
  .values()
];

console.log(res);
<iframe name="sif2" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>

  • Related