ServiceNow IC2 | HM Round Interview – JavaScript Deep Flatten + Type Grouping (with a Catch)
Summary
I had a Hiring Manager round interview at ServiceNow, where I was presented with a challenging JavaScript problem involving deep flattening an array, grouping its elements by type, and counting the frequency of unique values within each type. I successfully navigated the problem, including debugging a runtime error and addressing several follow-up questions, which led to a positive outcome.
Full Experience
💼 HM Round Interview – JavaScript Deep Flatten + Type Grouping (with a Catch)
🔹 Part 1: Main Problem Asked
"You're given a deeply nested array with all kinds of values (numbers, strings, booleans, null, undefined, functions, symbols, objects).
Write a function that:
- ✅ Deep flattens the array
- ✅ Groups elements by their JavaScript
typeof - ✅ Tracks the frequency count of each unique value within that type (This was the followup of the main question)
🔸 Sample Input:
const input = [1, 'a', [true, ['b', undefined], [{} , null]], () => {}, Symbol('x')];
🔸 Expected Output:
{
number: { '1': 1 },
string: { 'a': 1, 'b': 1 },
boolean: { 'true': 1 },
undefined: { 'undefined': 1 },
null: { 'null': 1 },
object: { '[object Object]': 1 },
function: { '() => {}': 1 },
symbol: { 'Symbol(x)': 1 }
}
🔹 Part 2: Follow-Up Challenge – Runtime Error & Fix
While implementing this, I hit a TypeError:
Cannot read properties of undefined (reading '1')
🐞 Root Cause:
if (!result[key]) {
result[key] = {};
}
❌ Incorrect check — I was initializing based on key (the value),
but should have checked result[type] instead (the group).
✅ Corrected Code:
if (!result[type]) {
result[type] = {};
}
🔍 Bonus Follow-Ups Asked:
- Why does
typeof null === 'object'?
→ Legacy bug. I handled it using:item === null ? 'null' : typeof item. - How did you stringify symbols safely for keys?
→ Useditem.toString()forSymbol(x)values. - What if you needed to keep raw values instead of string keys?
→ Suggested using aMapor{ value, count }objects instead of stringified keys.
✅ Outcome:
Handled edge cases, debugging, and recursion with safe typing and clean grouping logic.
Both versions of the solution:
✅ 1. With Frequency Count
function deepFlattenAndGroupByTypeWithFrequency(input) { const result = {};function recurse(arr) { for (const item of arr) { if (Array.isArray(item)) { recurse(item); // handle nested arrays } else { const type = item === null ? 'null' : typeof item; const key = typeof item === 'symbol' ? item.toString() : String(item);
if (!result[type]) { result[type] = {}; } result[type][key] = (result[type][key] || 0) + 1; } }}
recurse(input); return result; }
🔸 Output Example:
{
number: { '1': 2 },
string: { 'a': 2, 'b': 1 },
boolean: { 'true': 2 },
undefined: { 'undefined': 1 },
null: { 'null': 1 },
symbol: { 'Symbol(x)': 2 }
}
✅ 2. Without Frequency Count (Just grouping by type)
function deepFlattenAndGroupByType(input) { const result = {};function recurse(arr) { for (const item of arr) { if (Array.isArray(item)) { recurse(item); } else { const type = item === null ? 'null' : typeof item;
if (!result[type]) { result[type] = []; } result[type].push(item); } }}
recurse(input); return result; }
🔸 Output Example:
{
number: [1, 1],
string: ['a', 'a', 'b'],
boolean: [true, true],
undefined: [undefined],
null: [null],
symbol: [Symbol('x'), Symbol('x')]
}
Interview Questions (1)
You're given a deeply nested array with all kinds of values (numbers, strings, booleans, null, undefined, functions, symbols, objects).
Write a function that:
- ✅ Deep flattens the array
- ✅ Groups elements by their JavaScript
typeof - ✅ Tracks the frequency count of each unique value within that type (This was the followup of the main question)
🔸 Sample Input:
const input = [1, 'a', [true, ['b', undefined], [{} , null]], () => {}, Symbol('x')];
🔸 Expected Output:
{
number: { '1': 1 },
string: { 'a': 1, 'b': 1 },
boolean: { 'true': 1 },
undefined: { 'undefined': 1 },
null: { 'null': 1 },
object: { '[object Object]': 1 },
function: { '() => {}': 1 },
symbol: { 'Symbol(x)': 1 }
}