记一次js数组与树结构转换的操作

139 阅读2分钟

遍历数组

遍历tree,并console.log所有id

const tree = [  { id: '1',    children: [      { id: '1-1' },      { id: '1-2',        children: [          { id: '1-2-1' },          { id: '1-2-2' },          { id: '1-2-3' },        ]
      },
    ]
  },
  { id: '2',
    children: [
      { id: '2-1',
        children: [
          { id: '2-1-1' },
          { id: '2-1-2' },
          { id: '2-1-3' },
        ]
      },
      { id: '2-2' },
    ]
  },
  { id: '3' }
]

递归(经常用到)

function recursive(tree, cb) {
  tree?.forEach(item => {
    cb?.(item)
    recursive(item.children, cb) // 递归
  })
}
recursive(tree, item => console.log(item.id))

迭代

由于浏览器存在调用栈溢出情况(当然,一般我们遇不到),我们便使用迭代替代递归

function iteration(tree, cb) {
  const list = [...tree]
  while (list.length) { // 相当于迭代list
    const item = list.shift() // 从数组第一项取,直到取完
    cb?.(item)
    if (item.children) {
      list.unshift(...item.children) // 将子节点加到数组前面
    }
  }
}
iteration(tree, item => console.log(item.id))

数组转树

可能服务端偷懒,没有帮我们转换树结构,这个时候需要我们前端自行转换

const list = [
  { id: '1', text: '祖先1' },
  { id: '2', text: '祖先2' },
  { id: '3', text: '祖先3' },
  { id: '4', text: '子1', pid: '1' },
  { id: '5', text: '子2', pid: '2' },
  { id: '6', text: '子3', pid: '3' },
  { id: '7', text: '子3', pid: '3' },
  { id: '8', text: '叶子1', pid: '4' },
  { id: '9', text: '叶子2', pid: '4' },
  { id: '10', text: '叶子3', pid: '6' },
]
// 先混淆,表示祖先和叶子出现的顺序未定
function confusion(l = []) {
  return l.sort(() => 0.5 - Math.random())
}
const arr = confusion(list)

为了减少遍历次数,采用空间换时间,创建一个map<id, item>用于记录每一项。而后遍历时,添加至pid于map中存在的项中。如果pid于map中不存在,则先创建,等后续遍历到时再替换。

function listToTree(arr) {
  const map = new Map()
  arr.forEach((item) => {
    let pItem = map.get(item.pid)
    // 保证父项的存在
    if (!map.has(item.pid)) {
      map.set(item.pid, pItem = { children: [] })
    }
    if (!pItem.children) {
      pItem.children = []
    }
    // 将当前项添加至父项中
    pItem.children.push(item)

    // 如果之前存在,则替换
    if (map.has(item.id)) {
      item.children = map.get(item.id).children
    }
    // 将当前项添加至map中
    map.set(item.id, item)
  })
  // 获取,由于顶层pid不存在,则直接获取map中的undefined
  // 同时,我们也可以明确指出默认的顶层id来替代undefined
  return map.get().children
}
console.log(listToTree(arr))