Write code to count frequency of elements in an array - ["a", "b", "a", "c", "c", "d"]
Iterate once, accumulate counts in an object or Map. reduce((acc, x) => { acc[x] = (acc[x]||0)+1; return acc; }, {}). O(n) time, O(k) space. Discuss object vs Map (Map handles non-string keys, preserves insertion order, no prototype collisions).
Frequency counting is the canonical hash-map warm-up: one pass, accumulate counts.
With reduce into an object
function countFrequency(arr) {
return arr.reduce((acc, item) => {
acc[item] = (acc[item] || 0) + 1; // first time → 0, then +1
return acc;
}, {});
}
countFrequency(["a", "b", "a", "c", "c", "d"]);
// { a: 2, b: 1, c: 2, d: 1 }With a Map (the better default)
function countFrequency(arr) {
const freq = new Map();
for (const item of arr) {
freq.set(item, (freq.get(item) || 0) + 1);
}
return freq;
}Object vs Map — the talking point
A Map is usually the better choice and worth mentioning why:
- Any key type — objects, numbers, booleans as real keys. An object coerces all keys to strings (
1and"1"collide). - No prototype collisions — a plain object inherits keys like
constructor,toString. Counting an array containing"constructor"against{}gives surprising results. UseObject.create(null)if you stick with an object. - Preserves insertion order reliably and has a clean
.size/ iteration API.
For string keys in interview-scale code, an object is fine — but say you'd reach for Map for robustness.
Complexity
- Time: O(n) — single pass.
- Space: O(k) — k distinct elements.
Follow-ups to be ready for
- Most frequent element — track a running max while counting, or sort entries.
- First non-repeating element — count, then find the first with count 1.
- Group by a derived key — same pattern, key is
fn(item).
The framing
"One pass, accumulate into a hash map — reduce into an object, or a Map. acc[x] = (acc[x] || 0) + 1. O(n) time, O(k) space. I'd note that Map is the safer default: it allows non-string keys and avoids prototype-key collisions you get with a plain object — though for string keys at interview scale an object is fine. From here, most-frequent or first-non-repeating are small variations on the same count map."
Follow-up questions
- •Why might a Map be better than a plain object here?
- •How would you find the most frequent element?
- •How would you find the first non-repeating element?
- •What prototype-key collision could break the object version?
Common mistakes
- •Forgetting the `|| 0` fallback for the first occurrence.
- •Using a plain object and hitting prototype-key collisions (e.g. 'constructor').
- •Two passes when one suffices.
- •Not returning acc from the reduce callback.
Performance considerations
- •O(n) time, O(k) space — optimal; you must look at every element once. Map and object lookups are both ~O(1); Map can be marginally faster for frequent additions of varied keys.
Edge cases
- •Empty array — returns {} / empty Map.
- •Array with elements named like Object.prototype properties.
- •Mixed types where 1 and '1' would collide in an object.
- •NaN as an element (Map handles it as a key; works fine).
Real-world examples
- •Tallying tag/category counts, vote counts, or log-event types.
- •Building a histogram for analytics.