Implement countBy() — Group and Count Array Elements

countBy(array, fn) groups array elements by the result of a function and returns a count of how many fall into each group. It's a single reduce call — the challenge is getting the shape right.

7 min read
JavaScript
Interview
Implementation
Arrays

TABLE OF CONTENTS

countBy(array, fn) groups array elements by the result of a key function and returns a count of how many fall into each group. It's a single reduce call — the challenge is getting the accumulator shape and key resolution right.


What is countBy()?

countBy(array, fn) groups elements by the result of a key function and returns an object mapping each key to the count of elements that produced it. For [1, 2, 3, 4, 5] with fn = n => n % 2 === 0 ? "even" : "odd", the result is { even: 2, odd: 3 }.

It's a single reduce call with an accumulator object. For each element, compute the key via fn(element), then increment acc[key] (initializing to 0 if it doesn't exist). The entire function is a 3-line reduce.

This is a special case of the more general groupBy pattern — instead of collecting elements into arrays ({ even: [2, 4], odd: [1, 3, 5] }), you only keep the count. The count-only version is simpler because you don't need to manage arrays, just increment numbers.

Real-world use cases:

  • Vote tallyingcountBy(votes, v => v.candidate) to get per-candidate totals
  • Histogram binscountBy(data, d => Math.floor(d / 10) * 10) to bucket numeric data into ranges
  • Error categorizationcountBy(errors, e => e.code) to find the most frequent error type
  • Feature flagscountBy(users, u => u.variant) to verify A/B test distribution

The interview tests reduce mechanics, the (acc[key] || 0) + 1 initialization pattern, and whether you can transform a general grouping problem into a counting-specific solution.


The Problem

"Implement countBy(array, fn) that returns an object where each key is the result of calling fn on an element, and each value is the number of elements that produced that key."


Thought Process

You're creating a frequency map. The accumulator is a plain object:

  • For each element, compute the key via fn(element)
  • Increment the count at that key (default to 0 if absent)
  • Return the accumulator

reduce is the natural fit. The initial value is {}.


Step 1 — Base with reduce

Loading editor...


Step 2 — Supporting String Keys (Shortcut)

The interviewer says: "What if fn is a string? Use it as a property name."

Loading editor...


Step 3 — Extension: groupBy

The interviewer extends: "Now implement groupBy — collect the elements instead of counting them."

Loading editor...


Step 4 — Edge Cases

Empty array: reduce with an empty array and initial value {} returns {}. Correct.

Key function returns undefined: undefined becomes an object key: { undefined: N }. This matches lodash's countBy behavior. The interviewer may want you to handle it by skipping or using a default key — ask.

Key function returns non-string: Object keys are always strings. countBy([1], n => n) produces { '1': 1 }, not { 1: 1 }. This is correct — numbers get stringified naturally.

Null/undefined in array: fn(null) might return a key or throw. Your function should handle whatever fn returns.


Full Solution

Loading editor...


What Interviewers Are Testing

  • Reduce comfort — recognizing that frequency counting is a reduce operation
  • Shorthand syntax — supporting both (item) => key and 'propertyName'
  • Accumulator mutation pattern — creating/modifying keys in the accumulator object
  • Extension to groupBy — showing the pattern generalizes from counting to collecting

Complexity

TimeSpace
countByO(N)O(K) — K unique keys
groupByO(N)O(N) — stores all elements

Interview Tips

  • Write reduce confidently — "This is a frequency map — reduce into an object with key counts." Don't write a for loop first and then refactor.
  • Support the property-name shortcutcountBy(users, 'role') is the lodash convention. Adding it without being asked shows library awareness.
  • Show groupBy as the natural sibling — "Once you have countBy, groupBy is the same thing but collecting elements into arrays instead of incrementing numbers."
  • Handle default initialization cleanlyacc[key] = (acc[key] || 0) + 1 is the standard one-liner. Don't write if (!acc[key]) acc[key] = 0; acc[key]++.

Related Questions


Let's Connect

© 2026 Naveen Karthik // Built with React & MUI