需求:實(shí)現(xiàn)如下圖所示標(biāo)簽樹(shù)
https://i.postimg.cc/VkrwLQ5p/911.png
數(shù)據(jù)庫(kù)
| id | name | game_id | first_classify | second_classify |
|---|---|---|---|---|
| 1 | 標(biāo)簽1 | test123mumu | 1 | 2 |
| 2 | 標(biāo)簽2 | test123mumu | 1 | 2 |
| 3 | 標(biāo)簽3 | test123mumu | 1 | 2 |
| 4 | 標(biāo)簽4 | test123mumu | 1 | 3 |
| 5 | 標(biāo)簽5 | test123mumu | 1 | 4 |
| 6 | 標(biāo)簽6 | test123mumu | 6 | 6 |
| 7 | 標(biāo)簽7 | test123mumu | 7 | 7 |
| 8 | 標(biāo)簽8 | test123mumu | 4 | 4 |
| 9 | 場(chǎng)景 | test123mumu | ||
| 10 | 男 | test123mumu | 性別 | |
| 11 | 女 | test123mumu | 性別 | |
| 12 | 中 | test123mumu | 性質(zhì) |
思路
主要思路是通過(guò)迭代 results(數(shù)據(jù)庫(kù)中查出的全部數(shù)據(jù)) 中的每個(gè)標(biāo)簽,將它們組織成樹(shù)形結(jié)構(gòu)。首先,檢查標(biāo)簽的分類層級(jí)(第一級(jí)和第二級(jí)),并根據(jù)需要?jiǎng)?chuàng)建新的樹(shù)節(jié)點(diǎn)。然后,將當(dāng)前標(biāo)簽作為子節(jié)點(diǎn)添加到相應(yīng)的位置。最終,返回構(gòu)建的樹(shù)節(jié)點(diǎn)列表。
代碼實(shí)現(xiàn)
func tree(results []*model.ArtMaterialTag) []*bean.Tree {
// 創(chuàng)建一個(gè)空的樹(shù)節(jié)點(diǎn)列表
list := make([]*bean.Tree, 0)
// 創(chuàng)建兩個(gè)映射,用于跟蹤第一級(jí)和第二級(jí)分類的索引位置
firstIndexMapping, secondIndexMapping := make(map[string]int), make(map[string]int)
// 遍歷給定的結(jié)果列表
for _, tag := range results {
// 初始化一些變量
firstIndex, secondIndex, haveFirst, haveSecond := 0, 0, false, false
// 創(chuàng)建一個(gè)樹(shù)節(jié)點(diǎn),并填充其屬性
node := bean.Tree{
ID: tag.ID,
Label: tag.Name,
Children: make([]bean.Tree, 0),
}
// 處理第一級(jí)分類
if tag.FirstClassify != constants.EmptyString {
haveFirst = true
// 檢查第一級(jí)分類是否已經(jīng)存在于列表中,如果不存在,則創(chuàng)建一個(gè)新的節(jié)點(diǎn)
v, ok := firstIndexMapping[tag.FirstClassify]
if !ok {
list = append(list, &bean.Tree{Label: tag.FirstClassify, Children: make([]bean.Tree, 0)})
firstIndexMapping[tag.FirstClassify] = len(list) - 1
firstIndex = len(list) - 1
} else {
firstIndex = v
}
}
// 處理第二級(jí)分類
if tag.SecondClassify != constants.EmptyString {
haveSecond = true
// 創(chuàng)建一個(gè)用于唯一標(biāo)識(shí)第二級(jí)分類的鍵
key := tag.FirstClassify + "-" + tag.SecondClassify
// 檢查第二級(jí)分類是否已經(jīng)存在于列表中,如果不存在,則創(chuàng)建一個(gè)新的節(jié)點(diǎn)
v, ok := secondIndexMapping[key]
if !ok {
list[firstIndex].Children = append(list[firstIndex].Children, bean.Tree{Label: tag.SecondClassify, Children: make([]bean.Tree, 0)})
secondIndexMapping[key] = len(list[firstIndex].Children) - 1
secondIndex = len(list[firstIndex].Children) - 1
} else {
secondIndex = v
}
}
// 將當(dāng)前節(jié)點(diǎn)添加到樹(shù)的相應(yīng)位置
if haveSecond {
list[firstIndex].Children[secondIndex].Children = append(list[firstIndex].Children[secondIndex].Children, node)
} else if haveFirst {
list[firstIndex].Children = append(list[firstIndex].Children, node)
} else {
list = append(list, &node)
firstIndexMapping[tag.FirstClassify] = len(list) - 1
}
}
// 返回構(gòu)建的樹(shù)節(jié)點(diǎn)列表
return list
}
代碼核心解讀
firstIndexMapping 和 secondIndexMapping 是兩個(gè)映射,它們用于跟蹤已經(jīng)存在的第一級(jí)和第二級(jí)分類在樹(shù)結(jié)構(gòu)中的索引位置。這兩個(gè)映射的目的是為了避免重復(fù)創(chuàng)建相同的分類節(jié)點(diǎn),以及在需要時(shí)能夠快速找到已經(jīng)存在的節(jié)點(diǎn)位置。以下是它們?cè)诖a中的作用和思路:
- firstIndexMapping 映射:
- 這個(gè)映射的鍵是第一級(jí)分類的名稱(tag.FirstClassify)。
- 對(duì)應(yīng)的值是該分類在 list 樹(shù)節(jié)點(diǎn)列表中的索引位置。
- 如果某個(gè)第一級(jí)分類在 firstIndexMapping 中不存在,那么代碼會(huì)創(chuàng)建一個(gè)新的樹(shù)節(jié)點(diǎn)表示該分類,并將它添加到 list 中,然后將新節(jié)點(diǎn)的索引位置存儲(chǔ)在 firstIndexMapping 中。如果已經(jīng)存在,代碼會(huì)直接獲取該分類在 list 中的索引位置。
- secondIndexMapping 映射:
- 這個(gè)映射的鍵是一個(gè)組合鍵,由第一級(jí)分類和第二級(jí)分類組合而成(tag.FirstClassify + "-" + tag.SecondClassify)。
- 對(duì)應(yīng)的值是第二級(jí)分類在其父節(jié)點(diǎn)(第一級(jí)分類節(jié)點(diǎn))的子節(jié)點(diǎn)列表中的索引位置。
- 如果某個(gè)第二級(jí)分類在 secondIndexMapping 中不存在,那么代碼會(huì)創(chuàng)建一個(gè)新的樹(shù)節(jié)點(diǎn)表示該分類,并將它添加到其父節(jié)點(diǎn)的子節(jié)點(diǎn)列表中,然后將新節(jié)點(diǎn)的索引位置存儲(chǔ)在 secondIndexMapping 中。如果已經(jīng)存在,代碼會(huì)直接獲取該分類在其父節(jié)點(diǎn)的子節(jié)點(diǎn)列表中的索引位置。
這兩個(gè)映射的使用可以有效地構(gòu)建樹(shù)結(jié)構(gòu),確保相同分類不會(huì)重復(fù)創(chuàng)建,而是被添加到已有的分類節(jié)點(diǎn)下。這有助于提高代碼的效率和減少內(nèi)存消耗,同時(shí)確保最終的樹(shù)形結(jié)構(gòu)正確反映了分類的層次關(guān)系。
返回json結(jié)果示例
{
"code": 0,
"message": "",
"data": [
{
"id": 0,
"label": "1",
"children": [
{
"id": 0,
"label": "2",
"children": [
{
"id": 1,
"label": "標(biāo)簽1",
"children": []
},
{
"id": 2,
"label": "標(biāo)簽2",
"children": []
},
{
"id": 3,
"label": "標(biāo)簽3",
"children": []
}
]
},
{
"id": 0,
"label": "3",
"children": [
{
"id": 4,
"label": "標(biāo)簽4",
"children": []
}
]
},
{
"id": 0,
"label": "4",
"children": [
{
"id": 5,
"label": "標(biāo)簽5",
"children": []
}
]
}
]
},
{
"id": 0,
"label": "6",
"children": [
{
"id": 0,
"label": "6",
"children": [
{
"id": 6,
"label": "標(biāo)簽6",
"children": []
}
]
}
]
},
{
"id": 0,
"label": "7",
"children": [
{
"id": 0,
"label": "7",
"children": [
{
"id": 7,
"label": "標(biāo)簽7",
"children": []
},
{
"id": 15,
"label": "測(cè)試第二二條",
"children": []
}
]
}
]
},
{
"id": 0,
"label": "4",
"children": [
{
"id": 0,
"label": "4",
"children": [
{
"id": 8,
"label": "標(biāo)簽8",
"children": []
},
{
"id": 13,
"label": "標(biāo)簽9",
"children": []
}
]
}
]
},
{
"id": 9,
"label": "場(chǎng)景",
"children": []
},
{
"id": 0,
"label": "性別",
"children": [
{
"id": 10,
"label": "男",
"children": []
},
{
"id": 11,
"label": "女",
"children": []
}
]
},
{
"id": 0,
"label": "性質(zhì)",
"children": [
{
"id": 12,
"label": "中",
"children": []
}
]
},
{
"id": 0,
"label": "3",
"children": [
{
"id": 0,
"label": "4",
"children": [
{
"id": 14,
"label": "測(cè)試第一條",
"children": []
},
{
"id": 16,
"label": "測(cè)試第一個(gè)餓",
"children": []
}
]
}
]
}
]
}