算法使用场景笔记

447 阅读3分钟

前言:

算法,在我们开发过程中,很常见,但实现复杂的场景,对算法的要求还是很高,所以作为一个想晋级,突破瓶颈的你我,都要重视基础,深入算法以及数据结构,接下来根据最近处理的一个场景来回忆,复习,进而记录温故知新

实现一个动态列展示

        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常用的遍历