Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

树状数组结构转化 | 开箱即用的代码块 #20

Open
OBKoro1 opened this issue Aug 1, 2019 · 0 comments
Open

树状数组结构转化 | 开箱即用的代码块 #20

OBKoro1 opened this issue Aug 1, 2019 · 0 comments

Comments

@OBKoro1
Copy link
Owner

OBKoro1 commented Aug 1, 2019

博客链接

# 树状数组结构转化

# 题目如下:

这道题是我朋友发给我的,之前一开始看的时候,觉得很简单,但仔细往下看的时候,眉头一皱发现事情并不简单。

PS:这类题目之前也以不同形式出现过

# 传进去的数组:

let oldArr = [
  {
    '1_class': '工具',
    '2_class': '备忘录',
    '1_id': 1,
    '2_id': 2
  },
  {
    '1_class': '教育',
    '2_class': '学历教育',
    '3_class': '中等',
    '1_id': 3,
    '2_id': 4,
    '3_id': 6
  },
  {
    '1_class': '教育',
    '2_class': '学历教育',
    '3_class': '高等',
    '1_id': 3,
    '2_id': 4,
    '3_id': 5
  },
  {
    '1_class': '教育',
    '2_class': '成人教育',
    '1_id': 3,
    '2_id': 7
  }
];

# 输出的数组:

let result = [
  {
    value: 1,
    label: '工具',
    children: [
      {
        value: 2,
        label: '备忘录',
        children: []
      }
    ]
  },
  {
    value: 3,
    label: '教育',
    children: [
      {
        value: 4,
        label: '学历教育',
        children: [
          {
            value: 6,
            label: '中等',
            children: []
          },
          {
            value: 5,
            label: '高等',
            children: []
          }
        ]
      },
      {
        value: 7,
        label: '成人教育',
        children: []
      }
    ]
  }
];

# 建议大家好好想想,争取能够自己解出来

# 参考一下我的解题方法:

  1. 先算出层级嵌套数

    遍历数组,再遍历数组的元素,用parseInt拿到每一个值,将最大的值取出来,即为层级嵌套数。

  2. 数组转成属性层级的对象。对象的属性是层级,值是数组,层级里面的值。

    1.去重操作(比如:1_id相等的话就不再重复添加)

    2.提取需要的信息,最终的值和相应父级的信息(之后组装数组的时候放到对应的地方,需要的信息)。

    最后输出的对象是这个样子

  1. 将属性层级的对象转成树状结构数组。

    遍历对象,获取层级值。

    遍历层级的每个元素。

    找到对应的层级将值添加进去,否则递归继续找对应层级。

# 代码:

let listToTree = arr => {
  let [levelNum, newArr, obj] = [1, [], {}];
  // 层级嵌套数
  arr.forEach(item => {
    for (let proto in item) {
      let protoLevel = parseInt(proto);
      if (levelNum < protoLevel) levelNum = protoLevel; // 总共多少层级
    }
  });
  // 分开层级 放在一个对象中
  for (let i = 1; i < levelNum + 1; i++) {
    levelClass(i);
  }
  // 将对象转化成数组
  Object.keys(obj).forEach(item => {
    let forNum = parseInt(item); // 当前层级数
    obj[item].forEach(itemChildren => {
      // 遍历每个层级的每个值
      packageArr(itemChildren, forNum, newArr);
    });
  });
  // 分开每个层级
  function levelClass(name) {
    arr.forEach(value => {
      // 每个元素都遍历一次 分开对应层级
      if (!value[`${name}_id`]) return; // 有的对象层级没那么多
      let objFor = {};
      // 其他层级的value 赋值
      for (let j = 1; j < name; j++) {
        objFor[`value${j}`] = value[`${j}_id`];
      }
      if (obj[`${name}_id`]) {
        // 相同层级不重复添加 比如第一层级 id都为1 只添加一个
        let status = obj[`${name}_id`].find(item => {
          return item.value === value[`${name}_id`];
        });
        // 没有才添加
        if (!status) {
          obj[`${name}_id`].push(
            Object.assign(objFor, {
              value: value[`${name}_id`],
              label: value[`${name}_class`]
            })
          );
        }
      } else {
        // 初始化创建一个数组
        obj[`${name}_id`] = [
          Object.assign(objFor, {
            value: value[`${name}_id`],
            label: value[`${name}_class`]
          })
        ];
      }
    });
  }
  // 组装每个值
  function packageArr(sureName, index, arr, key = 1) {
    if (key === index) {
      // 当key和index相同时 即找到当前层级
      return arr.push({
        value: sureName.value,
        label: sureName.label,
        children: []
      });
    } else {
      key++;
      // 当前层级数组中对应的对象元素
      let num = arr.findIndex(value => {
        return value.value === sureName[`value${key - 1}`];
      });
      // 继续找或者已经找到
      return packageArr(sureName, index, arr[num].children, key);
    }
  }
  return newArr;
};

# 更好的解决方式:只关注层级有没有被组装过

感谢MrHouBeiBei提供更好的解决方法:

function getNewArr(activeArr) {
  // 递归处理传进来的对象
  function fn(arr, obj, id) {
    var objLen = Object.keys(obj).length / 2; // 对象总共的层级
    var rtItem = arr.find(i => {
      return i.value === obj[`${id}_id`]; // 找该层级是否被组装过
    });
    // 没被组装过 就组装
    // 被组装就跳过(覆盖)
    if (!rtItem) {
      rtItem = {};
      rtItem.value = obj[`${id}_id`]; // 层级id
      rtItem.lable = obj[`${id}_class`];
      rtItem.children = [];
      arr.push(rtItem);
    }
    id++; // 准备组装下一层级
    // 如果层级结束就退出递归
    if (id > objLen) return;
    // 递归继续组装
    fn(rtItem.children, obj, id);
  }

var res = [];
for (let item of activeArr) {
// 遍历数组 处理每个对象
var id = 1;
fn(res, item, id);
}
return res;
}

# 点个Star支持我一下~

博客链接

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment