面試題——數組轉樹結構


      樹結構大家應該都比較熟悉,這里我主要說兩種:一個根節點和多個根節點。一個根節點,就像我們的html節點,不可能有和它同級的;多個根節點,比如我們的一二級導航欄。下面一個個分析:

一個根節點

初級 - 只能是兩層樹

let arr = [
  {
    menuId: 1,
    name: '系統1',
    parentMenu: null
  },
  {
    menuId: 2,
    name: '系統1_0',
    parentMenu: 1
  },
  {
    menuId: 3,
    name: '系統1_1',
    parentMenu: 1
  }
]

function turnToTreeOfOneRoot(arr) {
  if (!Array.isArray(arr)) {
    throw new Error('is not array')
  } else {
    return arr.reduce((cur, item) => {
      if (item.parentMenu == null) {
        cur = { children: [], ...item }
      } else if (item.parentMenu == cur.menuId) {
        cur.children.push(item)
      }

      return cur
    }, {})
  }
}

turnToTreeOfOneRoot(arr)

升級 - 隨便幾層

var arr1 = [
  {
    menuId: 1,
    name: '系統管理1',
    parentMenu: null
  },
  {
    menuId: 2,
    name: '系統管理1_0',
    parentMenu: 1
  },
  {
    menuId: 3,
    name: '系統管理1_1',
    parentMenu: 1
  },
  {
    menuId: 4,
    name: '系統管理2_0',
    parentMenu: 2
  }
]

function turnToTreeOfOneRootPlus(arr) {
  var obj = {}
  arr.forEach(item => {
    if (item.parentMenu == null) {
      obj = item
    }
  })

  return arr.reduce((h, m) => {
    // 如果不是根節點
    if (m.parentMenu) {
      foo(h, m)
    }

    // 在obj里面為cur找到歸宿
    function foo(obj, cur) {
      if (obj.menuId === cur.parentMenu) {
        if (!obj.children) {
          obj.children = []
        }
        obj.children.push(cur)
      } else if (obj.children) {
        obj.children.forEach(item => {
          foo(item, cur)
        })
      }
    }

    return h
  }, obj)
}

turnToTreeOfOneRootPlus(arr1)

多個根節點

初級 - 只能是兩層樹

let arr2 = [
  {
    menuId: 1,
    name: '系統1',
    parentMenu: null
  },
  {
    menuId: 2,
    name: '系統1_0',
    parentMenu: 1
  },
  {
    menuId: 3,
    name: '系統1_1',
    parentMenu: 1
  },
  {
    menuId: 4,
    name: '系統2',
    parentMenu: null
  },
  {
    menuId: 5,
    name: '系統4_0',
    parentMenu: 4
  }
]

function turnToTreeOfManyRoot(arr) {
  if (!Array.isArray(arr)) {
    throw new Error('is not array')
  } else {
    var roots = []
    arr.forEach(item => {
      if (item.parentMenu == null) {
        item.children = []
        roots.push(item)
      }
    })

    return arr.reduce((roots, cur) => {
      roots.forEach(item => {
        // 如果是根節點
        if (item.menuId == cur.parentMenu) {
          item.children.push(cur)
        }
      })

      return roots
    }, roots)
  }
}

turnToTreeOfManyRoot(arr2)

升級 - 隨便幾層

var arr3 = [
  {
    menuId: 1,
    name: '系統管理1',
    parentMenu: null
  },
  {
    menuId: 2,
    name: '系統管理2',
    parentMenu: null
  },
  {
    menuId: 3,
    name: '系統管理1_0',
    parentMenu: 1
  },
  {
    menuId: 4,
    name: '系統管理1_1',
    parentMenu: 1
  },
  {
    menuId: 5,
    name: '系統管理2_0',
    parentMenu: 2
  },
  {
    menuId: 6,
    name: '系統管理5_0',
    parentMenu: 5
  },
  {
    menuId: 7,
    name: '系統管理3',
    parentMenu: null
  }
]

function turnToTreeOfManyRootPlus(arr) {
  var arrs = []
  arr.forEach(item => {
    if (!item.parentMenu) {
      arrs.push(item)
    }
  })

  return arr.reduce((h, m) => {
    if (m.parentMenu) {
      foo(h, m)
    }

    function foo(arr, cur) {
      arr.forEach(item => {
        if (item.menuId === cur.parentMenu) {
          if (!item.children) {
            item.children = []
          }
          item.children.push(cur)
        } else if (item.children) {
          foo(item.children, cur)
        }
      })
    }

    return h
  }, arrs)
}

turnToTreeOfManyRootPlus(arr3)

ps:最后提醒一下,數組里面的對象一定是排序過的,也就是說父級一定在前面,它的子級一定在后面。比如:

let arr = [
  {
    menuId: 1,
    name: '系統1',
    parentMenu: null
  },
  {
    menuId: 4,
    name: '系統2_0',
    parentMenu: 2
  },
  {
    menuId: 2,
    name: '系統1_0',
    parentMenu: 1
  },
  {
    menuId: 3,
    name: '系統1_1',
    parentMenu: 1
  }
]

這樣的數組,會導致menuId: 4丟失。因為它的父級在后面,所以遍歷到它時沒辦法塞給它的父級。謹記:一定要排好序,然后進行數組遍歷


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM