Back to DSA & Algorithms
DSA & Algorithms
easy
mid

How would you find the frequency of each element in an array?

Reduce into a Map (or plain object): for each element, increment its count. `new Map` if keys may be objects or non-strings; object literal if all keys are strings/numbers (faster lookup, JSON-friendly). `Object.create(null)` to avoid prototype-chain key collisions like `__proto__`.

3 min read·~6 min to think through

Common interview warm-up; also a real pattern for cardinality histograms.

Map version (keys can be anything)

js
function freq(arr) {
  const m = new Map();
  for (const x of arr) m.set(x, (m.get(x) ?? 0) + 1);
  return m;
}

freq(["a", "b", "a", "c", "b", "a"]);
// Map { "a" => 3, "b" => 2, "c" => 1 }

Map accepts any key (objects, NaN, etc.), preserves insertion order, and has O(1) get/set.

Object version (string/number keys)

js
function freq(arr) {
  const out = Object.create(null);
  for (const x of arr) out[x] = (out[x] ?? 0) + 1;
  return out;
}

Object.create(null) avoids inherited keys (so __proto__, constructor etc. are normal keys, not booby traps).

Reduce version

js
const freq = (arr) => arr.reduce((acc, x) => ((acc[x] = (acc[x] ?? 0) + 1), acc), Object.create(null));

Compact, same shape.

Sorted by count

js
function topByFreq(arr, k) {
  const m = freq(arr);
  return [...m.entries()].sort((a, b) => b[1] - a[1]).slice(0, k);
}

Bucket sort for top-k frequencies (O(n))

js
function topK(arr, k) {
  const m = freq(arr);
  const buckets = Array(arr.length + 1).fill(null).map(() => []);
  for (const [v, c] of m) buckets[c].push(v);
  const out = [];
  for (let i = buckets.length - 1; i >= 0 && out.length < k; i--) {
    for (const v of buckets[i]) {
      out.push(v);
      if (out.length === k) break;
    }
  }
  return out;
}

Linear-time top-k by frequency — better than sort for large n.

Edge cases

  • Empty array → empty Map/object.
  • NaN as a key → Map handles it; plain object coerces to "NaN" string.
  • null / undefined → object coerces to "null" / "undefined"; Map keeps them distinct.
  • Object keys → only Map handles; plain object stringifies to "[object Object]" for all → collisions.
  • Symbols → can't be keys in plain object lookup the same way.

Interview framing

"Reduce into a Map, incrementing per element — O(n), O(distinct) memory. Plain object is fine for string/number keys; use Object.create(null) to avoid prototype collisions. Map if keys can be objects or you need insertion order. For top-k by frequency without sorting, bucket sort by count is O(n). Edge cases: NaN, null, object keys — all only work cleanly with Map."

Follow-up questions

  • When to use Map vs object?
  • How would you find the top-k most frequent?
  • What's the time complexity?

Common mistakes

  • Using plain object with object keys.
  • Forgetting prototype-chain hazards (use Object.create(null)).
  • Re-traversing the array per element (O(n²)).

Performance considerations

  • Single pass O(n). Map.get/set is O(1) amortized. Bucket sort beats sort for top-k.

Edge cases

  • NaN, null, undefined keys.
  • Very large arrays — memory of the Map.
  • Symbol keys.

Real-world examples

  • Analytics distribution, word frequency, top tags, leaderboards.

Senior engineer discussion

Seniors choose Map for unknown key shape, use Object.create(null) when sticking with objects, and reach for bucket sort when top-k by frequency is the actual ask.

Related questions