Advanced JS

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); // 45

On this page