AlexB
AlexB

Reputation: 3548

Count elements that have the same value for a specific property and put the result in an array of objects

Using Array.reduce, I am trying to count the elements that have the same value for a specific property. I want to put the result in an array of objects containing a property for the value of the grouped by property and another one for the count. How can I do this easily in javascript ?

const CATEGORY = {
  STRATEGY: 'STRATEGY',
  CONTENT: 'CONTENT',
  ADVERTISING: 'ADVERTISING',
  MEASURMENT: 'MEASURMENT'
}

const lessons = [
  {
    title: 'ohoho',
    category: CATEGORY.STRATEGY
  }, {
    title: 'hihihi',
    category: CATEGORY.CONTENT
  }, {
    title: 'hello',
    category: CATEGORY.CONTENT
  }
]

let categoryLessonCount = lessons.reduce(function (acc, lesson) {
  acc[lesson.category] ? acc[lesson.category]++ : acc[lesson.category] = 1
  return acc
}, {})
console.log(categoryLessonCount[CATEGORY.STRATEGY])
console.log(categoryLessonCount[CATEGORY.CONTENT])
Actual categoryLessonCount value :

Object
{
  STRATEGY: 1, 
  CONTENT: 2
}

Wanted categoryLessonCount value :

Array
[ 
  {
   title: 'STRATEGY', 
   count: 1
  }, {
   title: 'CONTENT', 
   count: 2
  } 
]

Upvotes: 2

Views: 109

Answers (3)

RomanPerekhrest
RomanPerekhrest

Reputation: 92854

Short solution using Object.keys and Array.prototype.map functions:

...
let categoryLessonCount = lessons.reduce(function (acc, lesson) {
  acc[lesson.category] ? acc[lesson.category]++ : acc[lesson.category] = 1
  return acc
}, {})

let counts = Object.keys(categoryLessonCount).map(
  (k) => ({title: k, count: categoryLessonCount[k]})
)

console.log(counts);

Upvotes: 1

aw04
aw04

Reputation: 11177

Something like this should work:

let categoryLessonCount = lessons.reduce(function(acc, lesson) {
  let found = false
  for (const item of acc) {
    if (item.title === lesson.category) {
      item.count++
      found = true
    }
  }

  if (!found) {
    acc.push({
      title: lesson.category,
      count: 1
    })
  }

  return acc
}, [])

Your main issue is that your accumulating an object but expecting an array (note the final argument to reduce).

Upvotes: 1

ibrahim mahrir
ibrahim mahrir

Reputation: 31682

You already got the what you want just transform it into an array

const CATEGORY = {
  STRATEGY: 'STRATEGY',
  CONTENT: 'CONTENT',
  ADVERTISING: 'ADVERTISING',
  MEASURMENT: 'MEASURMENT'
}

const lessons = [{
  title: 'ohoho',
  category: CATEGORY.STRATEGY
}, {
  title: 'hihihi',
  category: CATEGORY.CONTENT
}, {
  title: 'hello',
  category: CATEGORY.CONTENT
}]

let count = lessons.reduce(function(acc, lesson) {
  acc[lesson.category] ? acc[lesson.category] ++ : acc[lesson.category] = 1
  return acc
}, {})

// transform count into what you want
let categoryLessonCount = [];
for (let cat in count) {
  categoryLessonCount.push({
    'title': cat,
    'count': count[cat]
  });
}

console.log(categoryLessonCount)

Upvotes: 1

Related Questions