Convert Nested Arrays to a JavaScript Dictionary
Convert deeply nested JavaScript arrays into object dictionaries for fast lookup, traversal, and category data access.
Dictionary of Nested Arrays
Nested arrays are convenient for rendering, but inefficient when you need direct access by id. Turning category data into dictionaries keeps lookup, update, and traversal code from repeatedly scanning every level.
Why it matters
When hierarchical data grows, repeated .find() or .filter() calls become noisy and expensive. A dictionary gives you:
- O(1) access to an item by
id - simpler updates, deletions, and traversal
- a good foundation for normalized frontend state
The progression is:
- A simple nested loop approach using JavaScript
- A recursive and reusable
mapToDictionary()helper - A strongly typed TypeScript version
Plain JavaScript: Nested Loop Approach
const data = [
{
id: 1,
name: "Category A",
items: [
{
id: 2,
name: "Subcategory A1",
items: [
{ id: 3, name: "Item A1-1", value: 10 },
{ id: 4, name: "Item A1-2", value: 15 },
],
},
{
id: 5,
name: "Subcategory A2",
items: [
{ id: 6, name: "Item A2-1", value: 20 },
{ id: 7, name: "Item A2-2", value: 25 },
],
},
],
},
{
id: 8,
name: "Category B",
items: [
{
id: 9,
name: "Subcategory B1",
items: [
{ id: 10, name: "Item B1-1", value: 30 },
{ id: 11, name: "Item B1-2", value: 35 },
],
},
{
id: 12,
name: "Subcategory B2",
items: [
{ id: 13, name: "Item B2-1", value: 40 },
{ id: 14, name: "Item B2-2", value: 45 },
],
},
],
},
];
function createNestedDictionary(data) {
const dictionary = {};
for (const category of data) {
dictionary[category.id] = { ...category, subcategories: {} };
for (const subcategory of category.items) {
dictionary[category.id].subcategories[subcategory.id] = {
...subcategory,
items: {},
};
for (const item of subcategory.items) {
dictionary[category.id].subcategories[subcategory.id].items[item.id] =
item;
}
}
}
return dictionary;
}
const nestedDictionary = createNestedDictionary(data);
console.log(nestedDictionary[1].name); // Category A
console.log(nestedDictionary[1].subcategories[5].name); // Subcategory A2
console.log(nestedDictionary[1].subcategories[5].items[7].name); // Item A2-2
console.log(nestedDictionary[8].subcategories[12].items[14]);
// { id: 14, name: 'Item B2-2', value: 45 }Recursive Helper: mapToDictionary()
The recursive version removes the hard-coded category/subcategory levels. Pass the output keys for each level, and the helper builds the same lookup shape from any compatible nested array.
const data = [
{
id: 1,
name: "Category A",
items: [
{
id: 2,
name: "Subcategory A1",
items: [
{ id: 3, name: "Item A1-1", value: 10 },
{ id: 4, name: "Item A1-2", value: 15 },
],
},
{
id: 5,
name: "Subcategory A2",
items: [
{ id: 6, name: "Item A2-1", value: 20 },
{ id: 7, name: "Item A2-2", value: 25 },
],
},
],
},
{
id: 8,
name: "Category B",
items: [
{
id: 9,
name: "Subcategory B1",
items: [
{ id: 10, name: "Item B1-1", value: 30 },
{ id: 11, name: "Item B1-2", value: 35 },
],
},
{
id: 12,
name: "Subcategory B2",
items: [
{ id: 13, name: "Item B2-1", value: 40 },
{ id: 14, name: "Item B2-2", value: 45 },
],
},
],
},
];
function mapToDictionary(data, keys) {
const [currentKey, ...remainingKeys] = keys;
return data.reduce((acc, item) => {
acc[item.id] = {
...item,
[currentKey || "items"]: item.items
? mapToDictionary(item.items, remainingKeys)
: undefined,
};
return acc;
}, {});
}
const nestedDictionary = mapToDictionary(data, ["subcategories", "items"]);
console.log(nestedDictionary[1].name); // Category A
console.log(nestedDictionary[1].subcategories[5].name); // Subcategory A2
console.log(nestedDictionary[1].subcategories[5].items[7].name); // Item A2-2
console.log(nestedDictionary[8].subcategories[9].items[11]);
// { id: 11, name: 'Item B1-2', value: 35, items: undefined }TypeScript: Fully Typed Nested Dictionary
The TypeScript version makes the expected structure explicit. This is helpful when the dictionary is passed between components or shared with state-management code.
type Item = {
id: number;
name: string;
value: number;
};
type Subcategory = {
id: number;
name: string;
items: Item[];
};
type Category = {
id: number;
name: string;
items: Subcategory[];
};
type Subcategories = Record<
number,
{
name: string;
items: Record<number, Item>;
}
>;
type NestedDictionary = Record<
number,
{
name: string;
subcategories: Subcategories;
}
>;
function mapItemsToDictionary(items: Item[]) {
return items.reduce(
(acc, item) => {
acc[item.id] = item;
return acc;
},
{} as Record<number, Item>,
);
}
function mapSubcategoriesToDictionary(subcategories: Subcategory[]) {
return subcategories.reduce((acc, subcategory) => {
acc[subcategory.id] = {
name: subcategory.name,
items: mapItemsToDictionary(subcategory.items),
};
return acc;
}, {} as Subcategories);
}
function createNestedDictionary(categories: Category[]): NestedDictionary {
return categories.reduce((acc, category) => {
acc[category.id] = {
name: category.name,
subcategories: mapSubcategoriesToDictionary(category.items),
};
return acc;
}, {} as NestedDictionary);
}
const data: Category[] = [
{
id: 1,
name: "Category A",
items: [
{
id: 2,
name: "Subcategory A1",
items: [
{ id: 3, name: "Item A1-1", value: 10 },
{ id: 4, name: "Item A1-2", value: 15 },
],
},
{
id: 5,
name: "Subcategory A2",
items: [
{ id: 6, name: "Item A2-1", value: 20 },
{ id: 7, name: "Item A2-2", value: 25 },
],
},
],
},
{
id: 8,
name: "Category B",
items: [
{
id: 9,
name: "Subcategory B1",
items: [
{ id: 10, name: "Item B1-1", value: 30 },
{ id: 11, name: "Item B1-2", value: 35 },
],
},
{
id: 12,
name: "Subcategory B2",
items: [
{ id: 13, name: "Item B2-1", value: 40 },
{ id: 14, name: "Item B2-2", value: 45 },
],
},
],
},
];
const nestedDictionary = createNestedDictionary(data);
console.log(nestedDictionary[1].name); // Category A
console.log(nestedDictionary[1].subcategories[5].name); // Subcategory A2
console.log(nestedDictionary[1].subcategories[5].items[7].name); // Item A2-2
console.log(nestedDictionary[8].subcategories[12].items[14].value); // 45Debounce and Throttle
Learn delay decorators, this-preserving timers, setTimeout, setInterval, debounce, and throttle in JavaScript.
Event Loop Execution Order
Learn JavaScript event loop behavior with promises, microtasks, macrotasks, async functions, setTimeout, blocking code, and requestAnimationFrame.