面試題——數組轉樹結構

樹結構你們應該都比較熟悉,這裏我主要說兩種:一個根節點和多個根節點。
一個根節點,就像咱們的html節點,不可能有和它同級的;多個根節點,好比咱們的一二級導航欄。
下面一個個分析: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:最後提醒一下,數組裏面的對象必定是排序過的,也就是說父級必定在前面,它的子級必定在後面。好比:json

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丟失。由於它的父級在後面,因此遍歷到它時沒辦法塞給它的父級。謹記:必定要排好序,而後進行數組遍歷數組

相關文章
相關標籤/搜索