面试题——数组转树结构

      树结构大家应该都比较熟悉,这里我主要说两种:一个根节点和多个根节点。一个根节点,就像我们的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丢失。因为它的父级在后面,所以遍历到它时没办法塞给它的父级。谨记:一定要排好序,然后进行数组遍历

posted @ 2019-07-07 22:03  奔跑的瓜牛  阅读(3168)  评论(0编辑  收藏  举报