Transform Lists and Nested Structures
This guide shows how to convert common data structures for better access, mutation, and integration — including lists, trees, dictionaries, and flattened arrays.
🔁 List to Tree
This utility transforms a flat list of items (with id
and parentId
fields) into a nested tree structure.
It uses a Map
to efficiently link children to their parents while preserving the hierarchy.
It also includes a treeToList()
function that flattens a tree back into a list — useful for data normalization,
storing tree nodes in databases, or syncing front-end trees with backend updates.
function listToTree(items) {
const map = new Map();
const roots = [];
// Map items by ID
for (const item of items) {
map.set(item.id, { ...item, children: [] });
}
for (const item of items) {
const node = map.get(item.id);
if (item.parentId === null) {
roots.push(node);
} else {
const parent = map.get(item.parentId);
if (parent) {
parent.children.push(node);
}
}
}
return roots;
}
const items = [
{ id: 1, name: "Root 1", parentId: null },
{ id: 2, name: "Child 1.1", parentId: 1 },
{ id: 3, name: "Child 1.2", parentId: 1 },
{ id: 4, name: "Root 2", parentId: null },
{ id: 5, name: "Child 2.1", parentId: 4 },
{ id: 6, name: "SubChild 2.1.1", parentId: 5 },
];
const tree = listToTree(items);
console.log(tree);
// [
// {
// "id": 1,
// "name": "Root 1",
// "parentId": null,
// "children": [
// {
// "id": 2,
// "name": "Child 1.1",
// "parentId": 1,
// "children": []
// },
// {
// "id": 3,
// "name": "Child 1.2",
// "parentId": 1,
// "children": []
// }
// ]
// },
// {
// "id": 4,
// "name": "Root 2",
// "parentId": null,
// "children": [
// {
// "id": 5,
// "name": "Child 2.1",
// "parentId": 4,
// "children": [
// {
// "id": 6,
// "name": "SubChild 2.1.1",
// "parentId": 5,
// "children": []
// }
// ]
// }
// ]
// }
// ]
function treeToList(tree) {
const list = [];
function traverse(node) {
const { children, ...rest } = node;
list.push(rest);
if (children) {
for (const child of children) {
traverse(child);
}
}
}
for (const root of tree) {
traverse(root);
}
return list;
}
const flatList = treeToList(tree);
console.log(flatList);
// [
// { id: 1, name: 'Root 1', parentId: null },
// { id: 2, name: 'Child 1.1', parentId: 1 },
// { id: 3, name: 'Child 1.2', parentId: 1 },
// { id: 4, name: 'Root 2', parentId: null },
// { id: 5, name: 'Child 2.1', parentId: 4 },
// { id: 6, name: 'SubChild 2.1.1', parentId: 5 }
// ]
🧩 Flat Nested Items (With Category + Subcategory)
Transforms deeply nested category-subcategory-item data into a flat array where each item contains metadata about its parent subcategory and category.
You can do it manually with loops or concisely with flatMap()
.
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 transformItems(data) {
const transformedItems = [];
for (const category of data) {
for (const subcategory of category.items) {
for (const item of subcategory.items) {
transformedItems.push({
id: item.id,
name: item.name,
value: item.value,
subcategory: subcategory.name,
category: category.name,
});
}
}
}
return transformedItems;
}
const itemsWithCategories = transformItems(data);
console.log(itemsWithCategories);
// [
// {
// id: 3,
// name: "Item A1-1",
// value: 10,
// subcategory: "Subcategory A1",
// category: "Category A",
// },
// {
// id: 4,
// name: "Item A1-2",
// value: 15,
// subcategory: "Subcategory A1",
// category: "Category A",
// },
// {
// id: 6,
// name: "Item A2-1",
// value: 20,
// subcategory: "Subcategory A2",
// category: "Category A",
// },
// {
// id: 7,
// name: "Item A2-2",
// value: 25,
// subcategory: "Subcategory A2",
// category: "Category A",
// },
// {
// id: 10,
// name: "Item B1-1",
// value: 30,
// subcategory: "Subcategory B1",
// category: "Category B",
// },
// {
// id: 11,
// name: "Item B1-2",
// value: 35,
// subcategory: "Subcategory B1",
// category: "Category B",
// },
// {
// id: 13,
// name: "Item B2-1",
// value: 40,
// subcategory: "Subcategory B2",
// category: "Category B",
// },
// {
// id: 14,
// name: "Item B2-2",
// value: 45,
// subcategory: "Subcategory B2",
// category: "Category B",
// },
// ];
function transformItems2(data) {
return data.flatMap((category) =>
category.items.flatMap((subcategory) =>
subcategory.items.map((item) => ({
id: item.id,
name: item.name,
value: item.value,
subcategory: subcategory.name,
category: category.name,
})),
),
);
}
const itemsWithCategories2 = transformItems2(data);
console.log(itemsWithCategories2);
// ...same result