前言:
算法,在我们开发过程中,很常见,但实现复杂的场景,对算法的要求还是很高,所以作为一个想晋级,突破瓶颈的你我,都要重视基础,深入算法以及数据结构,接下来根据最近处理的一个场景来回忆,复习,进而记录温故知新
实现一个动态列展示
let data = {}
let self = this
statEmpHourCodeSum({data}).then(res => {
if (res.data) {
let list = []
res.data.data.items.forEach((item, index) => {
self.tableParam.titles.push({
title: item.date,
align: 'center',
key: index + '',
width: 200
})
})
let items = res.data.data.items
// let codeLines = `${index}`
// list.push({userName: item.userName, [codeLines]: im.codeLines})
// 整合成对象
let dateLength = res.data.data.items.length
let tableList = []
let arr = []
let groupedList = []
items.map((item, index)=> {
item.items.forEach((im, index) => {
arr.push(im)
})
})
// 分组
groupedList = groupBy(arr, (item) => item.userName)
// 清理避免副作用
arr = []
// 对分组后的数据进行遍历
groupedList.map((im, index) => {
return groupedList[index].forEach(value => {
arr.push(value.codeLines)
})
})
// 整合数据预期渲染
for(let i=0;i <= arr.length/dateLength -1; i++) {
tableList.push({...arr.slice(dateLength*i,dateLength*i + dateLength)})
}
self.tableParam.data = tableList && tableList.map((item, index) => {
let currentRow = groupedList[index]
let currentData = currentRow[0]
item.userName = currentData.userName
let cells = []
item.cellClassName = {}
currentRow.forEach((im, index) => {
if (+im.codeLines > 42) {
cells.push({
[index]: 'table-cell-above-average'
})
} else {
cells.push({
[index]: 'table-cell-below-average'
})
}
})
let cellList = []
cells.forEach((item, index) => {
cellList.push(item[index])
})
// Object
item.cellClassName = {...cellList}
return item
})
self.tableParam.loading = false
}
}).catch()
}
上面一段代码,就是实现动态列的场景,复杂主要以下几点
1、返回的数据结构,很难找到规律
2、转换成对应结构,对算法的要求很高,需要很熟悉数组、对象以及灵活的转换
3、页面渲染,对每块cell的渲染加颜色,用索引作为列字段(想了很久才搞出来)
现在我们展开,上面代码一一解析
1、构造列头元素结构,并以index + '' 作为列字段,入栈titles数组
res.data.data.items.forEach((item, index) => {
self.tableParam.titles.push({
title: item.date,
align: 'center',
key: index + '',
width: 200
})
})
2、遍历数据结构,获取原子数据,入栈数组arr
let items = res.data.data.items
let arr = []
items.map((item, index)=> {
item.items.forEach((im, index) => {
arr.push(im)
})
})
3、分组-对入栈arr后的数组进行分组,目的为了行数据渲染
// 分组
groupedList = groupBy(arr, (item) => item.userName)
// 分组方法
/**
* @param {*} array 数组
* @param {*} f 函数对象 处理条件函数
* @description 按属性/字段分组
*/
export const groupBy = (array, f) => {
let groups = {}
array.forEach((o) => {
let group = JSON.stringify( f(o) )
groups[group] = groups[group] || []
groups[group].push(o)
});
return Object.keys(groups).map(( group ) => {
return groups[group]
});
}
4、分组后,清空原数组,避免副作用
// 清理避免副作用
arr = []
5、对分组后的数据进行遍历,重新入栈arr数组,存放某一数组,目的得到类似数组 [15,16,23,34]
// 对分组后的数据进行遍历
groupedList.map((im, index) => {
return groupedList[index].forEach(value => {
arr.push(value.codeLines)
})
})
6、对数组,按列表规则进行截取,分组,会分成类似 [15,16] [23,34] 数组,然后对数组集展开转换成对象 {0:15,1:16}
// 整合数据预期渲染
for(let i=0;i <= arr.length/dateLength -1; i++) {
tableList.push({...arr.slice(dateLength*i,dateLength*i + dateLength)})
}
公式
此公式【arr.slice(2i,2i + 2)】最终目的是将[15,16,23,34]变成类似这样[15,16] [23,34]
arr.slice(dateLength*i,dateLength*i + dateLength)
展开数组,为对象 {0:15, 1:16} {0:23,1:34}
{...arr.slice(dateLength*i,dateLength*i + dateLength)}
入栈tableList数组,最终形成[{0:15, 1:16},{0:23,1:34}]
tableList.push({...arr.slice(dateLength*i,dateLength*i + dateLength)})
7、遍历结构
[{0:15, 1:16}] 转换为 [0:{0:'table-cell-above-average'}, 1:{1:'table-cell-above-average'}]
通过这段代码`
let cellList = []
cells.forEach((item, index) => {
cellList.push(item[index])
})
// Object
item.cellClassName = {...cellList}
最终转换为[{0:'table-cell-above-average'},{1:'table-cell-above-average'}]
以此类推遍历,最终赋值给item.cellClassName对象 item.cellClassName = {...cellList}
self.tableParam.data = tableList && tableList.map((item, index) => {
let currentRow = groupedList[index]
let currentData = currentRow[0]
item.userName = currentData.userName
let cells = []
item.cellClassName = {}
currentRow.forEach((im, index) => {
if (+im.codeLines > 42) {
cells.push({
[index]: 'table-cell-above-average'
})
} else {
cells.push({
[index]: 'table-cell-below-average'
})
}
})
let cellList = []
cells.forEach((item, index) => {
cellList.push(item[index])
})
// Object
item.cellClassName = {...cellList}
return item
})
总结
以上代码,主要用到...展开和数组对象之间的转换,以及map,forEach,Object.keys常用的遍历