为 javascript 中多级类别的每个子项添加破折号

Add dash to each child of multi level category in javascript

我有一个像这样的多级类别数组:

[
        {
            "id": 5,
            "parent_id": 3,
            "name": "Fruits",
            "parent": {
                "id": 3,
                "parent_id": 1,
                "name": "Vegetables and fruits",
            }
        },
        {
            "id": 6,
            "parent_id": 3,
            "name": "Vegetables",
            "parent": {
                "id": 3,
                "parent_id": 1,
                "name": "Vegetables and fruits",
            }
        },
        {
            "id": 3,
            "parent_id": null,
            "name": "Vegetables and fruits",
            "parent": null
        },
]

我想根据级别为类别的每个子项添加“-”(破折号)前缀。例如,第一层有一个破折号'-',第三层有两个破折号'--'。

如何像这样更新数组?

我尝试了一些代码。

const updateData = (data) => {
    return data.map(item => {
        if (item.parent_id != null) {
            // Maybe there use recursive
            item.name = `-${item.name }`;
        }
        return item;
    })
}           

异常输出:

Vegetables and fruits
Drinks
-Fruits
-Vegetables
--Tomatos
--Potatos

我们可以创建一个 getLevel 函数来确定任何节点的级别,然后使用它来决定要使用的破折号数量:

let input = [ { "id": 5, "parent_id": 3, "name": "Fruits", "parent": { "id": 3, "parent_id": 1, "name": "Vegetables and fruits", } }, { "id": 6, "parent_id": 3, "name": "Vegetables", "parent": { "id": 3, "parent_id": 1, "name": "Vegetables and fruits", } }, { "id": 3, "parent_id": null, "name": "Vegetables and fruits", "parent": null }, { "id": 7, "parent_id": 5, "name": "Strawberries", "parent": { "id": 5, "parent_id": 3, "name": "Vegetables and fruits", } }, { "id": 8, "parent_id": 6, "name": "Tomatos", "parent": { "id": 6, "parent_id": 3, "name": "Vegetables and fruits", } }, ]

// Pre-compute object / parent mapping
const parentMap = input.reduce((acc,obj) => { 
    acc[obj.id] = obj?.parent;
    return acc;
}, {})

// Find the node level based on its parent id.
function getLevel(parentMap, obj) {
     let level = 0;
     while (parentMap[obj.id]) {
         level++;
         obj = parentMap[obj.id] 
     }
     return level;
}

const result = input.map(obj => {
    level = getLevel(parentMap , obj);
    return { ...obj, level} ;
})
.sort((a,b) => a.level - b.level)
.map(obj => '-'.repeat(obj.level) + obj.name)

console.log('Result:', result)

一种方法是将您的输入转换为树列表(因为您可以有单独的根)。然后,遍历它们并递归打印它们就变得非常容易了。这是我将使用的实现:

const input = [
        {
            "id": 5,
            "parent_id": 3,
            "name": "Fruits",
            "parent": {
                "id": 3,
                "parent_id": 1,
                "name": "Vegetables and fruits",
            }
        },
        {
            "id": 6,
            "parent_id": 3,
            "name": "Vegetables",
            "parent": {
                "id": 3,
                "parent_id": 1,
                "name": "Vegetables and fruits",
            }
        },
        {
            "id": 3,
            "parent_id": null,
            "name": "Vegetables and fruits",
            "parent": null
        },
]


function buildTrees(input) {
  const mapping = new Map()

    // Creating a mapping based on the item id
  input.forEach(i => {
    delete i.parent // parent detail is not needed
    i.children = []
    mapping.set(i.id, i)
  })

    // Adding every node to its parent children list
  input.filter(i => i.parent_id !== null).forEach(i => {
    mapping.get(i.parent_id).children.push(i)
  })

    // Returning the roots
  return input.filter(i => i.parent_id === null).map(i => mapping.get(i.id))
}

function printTree(tree, depth) {
    // Recursively prints the names
    console.log('-'.repeat(depth) + ' ' + tree.name)
  tree.children.forEach(child => printTree(child, depth + 1))
}

const trees = buildTrees(input)

trees.forEach(tree => printTree(tree, 0))