记录一次编程问题

先说问题

有如下一个数据,但它是用数组存放的具有联级关系的数据,需要将其转化为适合UI库的数据结构树状结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
const data = [
"办公设备、附件和用品>>办公用品>>书写工具>>毛笔",
"造纸原料和纸制品>>纸制品>>个人纸制品>>餐巾纸和餐巾",
"造纸原料和纸制品>>纸制品>>个人纸制品>>丝巾",
"办公设备、附件和用品>>办公用品>>测试分类>>苹果",
"其它",
"办公设备、附件和用品>>办公用品>>测试分类>>荔枝",
"办公设备、附件和用品>>家具用品>>床头用品>>枕头",
"食品、饮料和烟草>>肉和家禽产品>>加工和处理过的肉>>鲜的加工和处理过的肉",
"食品、饮料和烟草>>巧克力、糖、甜品和糖果>>糖果>>口香糖",
"食品、饮料和烟草>>饮料>>咖啡和茶>>咖啡饮料",
"食品、饮料和烟草>>饮料>>非酒精饮料>>泉水和矿泉水",
"办公设备、附件和用品>>办公用品>>书写工具>>水笔",
"造纸原料和纸制品>>纸制品>>个人纸制品>>纸巾",
"食品、饮料和烟草>>巧克力、糖、甜品和糖果>>巧克力、糖和甜品>>巧克力和巧克力代用品",
"食品、饮料和烟草>>饮料>>非酒精饮料>>水",
"食品、饮料和烟草>>乳制品和蛋>>牛奶和黄油产品>>贮藏的牛奶和黄油产品",
"食品、饮料和烟草>>预制食品和罐头>>方便什锦和用品>>方便什锦小吃",
"食品、饮料和烟草>>饮料>>咖啡和茶>>袋茶",
"食品、饮料和烟草>>面包和烘焙食品>>蛋糕、派和糕点>>新鲜蛋糕、派和糕点",
"休闲零食",
"食品、饮料和烟草>>饮料>>咖啡和茶>>非乳场生产的乳品饮料",
"服装、箱包、个人护理用品>>个人护理用品>>洗浴、身体护理品>>化妆品",
"食品、饮料和烟草>>饮料>>非酒精饮料>>软饮料",
"食品、饮料和烟草>>肉和家禽产品>>加工和处理过的肉>>贮藏加工和处理过的肉",
"食品、饮料和烟草>>谷类和豆类制品>>豆类>>豆粉",
"食品、饮料和烟草>>预制食品和罐头>>小吃>>坚果和水果干"
]

适合的结构如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
[
{
"value": "办公设备、附件和用品",
"lable": "办公设备、附件和用品",
"children": [
{
"value": "办公用品",
"lable": "办公用品",
"children": [
{
"value": "书写工具",
"lable": "书写工具",
"children": [
{
"value": "毛笔",
"lable": "毛笔"
}
...
]
}
...
]
}
...
]
}
]

首先的思路是切分字符串

使用String.prototype.split()将字符串切分为数组,方便分级

1
2
3
4
5
6
7
8
[
[ '办公设备、附件和用品', '办公用品', '书写工具', '毛笔' ],
[ '造纸原料和纸制品', '纸制品', '个人纸制品', '餐巾纸和餐巾' ],
[ '造纸原料和纸制品', '纸制品', '个人纸制品', '丝巾' ],
[ '办公设备、附件和用品', '办公用品', '测试分类', '苹果' ],
[ '其它' ],
...
]

简单点的就是死办法,看数据貌似只有4级,所以套四重循环就可以解决

但是这样真的很蠢,很笨,一旦数据发生变化,这就白写了

按照思路来先把数组中的字符串进行切分

1
2
3
4
5
6
const treeArr = []
const analysisData = (data) => { // 这样就得到了一个切分好的数组
data.forEach((ele, index) => {
treeArr.push(ele.split('>>'))
})
}

其次是观察数据结构

观察切分好的数据结构,有的是只有一级,没有子级的,有的呢,可能有四级也可能有三级。这样就对分级存放数据结构带来了很大的困扰。

这样就需要对每一条数据进行判断,这个判断的过程就抽出来写成一个函数就行了。

1
2
3
4
5
6
7
const treeArr = []
const analysisData = (data) => {
data.forEach(ele => {
const eleArr = ele.split('>>')
judgeData(treeArr, eleArr, 0)
})
}

这个函数接收3个传参

  • treeArr 存放预期数据结构的数组
  • eleArr 每一条原始的字符串切分数组
  • step 进行到第几步了

judgeData函数负责对传进来的每一条原始的字符串切分数组,进行判断,如果符合要求就push,不符合要求就递归判断,关键是递归的思想

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const judgeData = (treeArr, eleArr, step) => {
if (!treeArr.some(item => {
if (item.value === eleArr[step]) {
return true
}
})) {
const treeSon = {
value: eleArr[step],
lable: eleArr[step]
}
treeArr.push(treeSon)
if (eleArr[step + 1] !== undefined) {
treeSon.children = []
judgeData(treeSon.children, eleArr, step + 1)
}
} else {
treeArr.forEach(ele => {
if (ele.value === eleArr[step]) {
judgeData(ele.children, eleArr, step + 1)
}
})
}
}

treeArr传入的并不是预先在最开始设置的那个treeArr,而是每次存放预期数据结构的数组,因为js的对象是引用类型的所以,从对象上拆children下来传进去,并不影响存值,而step则是为了记录分级的层级,避免不知道到哪一步了,乱分。

这里贴上完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
const data = [
"办公设备、附件和用品>>办公用品>>书写工具>>毛笔",
"造纸原料和纸制品>>纸制品>>个人纸制品>>餐巾纸和餐巾",
"造纸原料和纸制品>>纸制品>>个人纸制品>>丝巾",
"办公设备、附件和用品>>办公用品>>测试分类>>苹果",
"其它",
"办公设备、附件和用品>>办公用品>>测试分类>>荔枝",
"办公设备、附件和用品>>家具用品>>床头用品>>枕头",
"食品、饮料和烟草>>肉和家禽产品>>加工和处理过的肉>>鲜的加工和处理过的肉",
"食品、饮料和烟草>>巧克力、糖、甜品和糖果>>糖果>>口香糖",
"食品、饮料和烟草>>饮料>>咖啡和茶>>咖啡饮料",
"食品、饮料和烟草>>饮料>>非酒精饮料>>泉水和矿泉水",
"办公设备、附件和用品>>办公用品>>书写工具>>水笔",
"造纸原料和纸制品>>纸制品>>个人纸制品>>纸巾",
"食品、饮料和烟草>>巧克力、糖、甜品和糖果>>巧克力、糖和甜品>>巧克力和巧克力代用品",
"食品、饮料和烟草>>饮料>>非酒精饮料>>水",
"食品、饮料和烟草>>乳制品和蛋>>牛奶和黄油产品>>贮藏的牛奶和黄油产品",
"食品、饮料和烟草>>预制食品和罐头>>方便什锦和用品>>方便什锦小吃",
"食品、饮料和烟草>>饮料>>咖啡和茶>>袋茶",
"食品、饮料和烟草>>面包和烘焙食品>>蛋糕、派和糕点>>新鲜蛋糕、派和糕点",
"休闲零食",
"食品、饮料和烟草>>饮料>>咖啡和茶>>非乳场生产的乳品饮料",
"服装、箱包、个人护理用品>>个人护理用品>>洗浴、身体护理品>>化妆品",
"食品、饮料和烟草>>饮料>>非酒精饮料>>软饮料",
"食品、饮料和烟草>>肉和家禽产品>>加工和处理过的肉>>贮藏加工和处理过的肉",
"食品、饮料和烟草>>谷类和豆类制品>>豆类>>豆粉",
"食品、饮料和烟草>>预制食品和罐头>>小吃>>坚果和水果干"
]
// console.log(data)
const treeArr = []
const analysisData = (data) => {
data.forEach(ele => {
const eleArr = ele.split('>>')
judgeData(treeArr, eleArr, 0)
})
}
const judgeData = (treeArr, eleArr, step) => {
if (!treeArr.some(item => {
if (item.value === eleArr[step]) {
return true
}
})) {
const treeSon = {
value: eleArr[step],
lable: eleArr[step]
}
treeArr.push(treeSon)
if (eleArr[step + 1] !== undefined) {
treeSon.children = []
judgeData(treeSon.children, eleArr, step + 1)
}
} else {
treeArr.forEach(ele => {
if (ele.value === eleArr[step]) {
judgeData(ele.children, eleArr, step + 1)
}
})
}
}
analysisData(data)
console.log('treeArr: ', JSON.stringify(treeArr))
作者

vear

发布于

2019-11-04

更新于

2022-01-03

许可协议

评论