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

第 88 题:实现 convert 方法,把原始 list 转换成树形结构,要求尽可能降低时间复杂度 #139

Open
yygmind opened this issue Jun 12, 2019 · 120 comments

Comments

@yygmind
Copy link
Contributor

yygmind commented Jun 12, 2019

以下数据结构中,id 代表部门编号,name 是部门名称,parentId 是父部门编号,为 0 代表一级部门,现在要求实现一个 convert 方法,把原始 list 转换成树形结构,parentId 为多少就挂载在该 id 的属性 children 数组下,结构如下:

// 原始 list 如下
let list =[
    {id:1,name:'部门A',parentId:0},
    {id:2,name:'部门B',parentId:0},
    {id:3,name:'部门C',parentId:1},
    {id:4,name:'部门D',parentId:1},
    {id:5,name:'部门E',parentId:2},
    {id:6,name:'部门F',parentId:3},
    {id:7,name:'部门G',parentId:2},
    {id:8,name:'部门H',parentId:4}
];
const result = convert(list, ...);

// 转换后的结果如下
let result = [
    {
      id: 1,
      name: '部门A',
      parentId: 0,
      children: [
        {
          id: 3,
          name: '部门C',
          parentId: 1,
          children: [
            {
              id: 6,
              name: '部门F',
              parentId: 3
            }, {
              id: 16,
              name: '部门L',
              parentId: 3
            }
          ]
        },
        {
          id: 4,
          name: '部门D',
          parentId: 1,
          children: [
            {
              id: 8,
              name: '部门H',
              parentId: 4
            }
          ]
        }
      ]
    },
  ···
];
@ZodiacSyndicate
Copy link

ZodiacSyndicate commented Jun 12, 2019

function convert(list) {
	const res = []
	const map = list.reduce((res, v) => (res[v.id] = v, res), {})
	for (const item of list) {
		if (item.parentId === 0) {
			res.push(item)
			continue
		}
		if (item.parentId in map) {
			const parent = map[item.parentId]
			parent.children = parent.children || []
			parent.children.push(item)
		}
	}
	return res
}

时间复杂度O(n)

@YouziXR
Copy link

YouziXR commented Jun 12, 2019

基本思路:
使用Map保存id和对象的映射,循环list,根据parentId在Map里取得父节点,如果父节点有children属性,就直接push当前的子节点,如果没有就添加children属性,最后遍历一遍list把parentId===0的节点取出来。

const convert = list => {
  let map = new Map();
  let result = []
  list.forEach(el => {
    map.set(el.id, el);
  });
  list.forEach(el => {
		let parent = map.get(el.parentId);
		if (!parent) {
			// parentId === 0
			el.children = []
			return 
		}
    if (parent.hasOwnProperty('children')) {
      parent.children.push(el);
    } else {
      parent['children'] = [];
      parent.children.push(el);
    }
	});
	for (let i = 0; i < list.length; i++) {
		const el = list[i];
		if (el.parentId === 0) {
			result.push(el)
		}
	}
	return result
};
let list = [
  { id: 1, name: '部门A', parentId: 0 },
  { id: 2, name: '部门B', parentId: 0 },
  { id: 3, name: '部门C', parentId: 1 },
  { id: 4, name: '部门D', parentId: 1 },
  { id: 5, name: '部门E', parentId: 2 },
  { id: 6, name: '部门F', parentId: 3 },
  { id: 7, name: '部门G', parentId: 2 },
  { id: 8, name: '部门H', parentId: 4 }
];
convert(list)

@lvwxx
Copy link

lvwxx commented Jun 12, 2019

function convert(arr) {
  const obj = {}
  const res = []
  list.forEach(item => {
    obj[item.id] = item
  })
  list.forEach(item => {
    if (item.parentId !== 0) {
      obj[item.parentId]['children'] ? obj[item.parentId]['children'].push(item) : obj[item.parentId]['children'] = [item]
    } else {
      res.push(item)
    }
  })
  return res
}

@dbl520
Copy link

dbl520 commented Jun 12, 2019

面试题:
有如下格式的原始数据:
var obj ={
"title":"颜色",
"items":[
{
"title":"黄色",
"flag":true,
"child":{
"title":"尺码",
"items":[
{
"title":"XL",
"flag":true,
"child":{
"title":"形状",
"items":[
{
"title":"多边形",
"flag":true,
"skuId":1
},
{
"title":"方形",
"flag":false,
"skuId":2
}
]
}
},
{
"title":"M",
"flag":false,
"child":{
"title":"形状",
"items":[
{
"title":"方形",
"flag":false,
"skuId":3
}
]
}
}
]
}
},
{
"title":"红色",
"flag":false,
"child":{
"title":"尺码",
"items":[
{
"title":"M",
"flag":false,
"child":{
"title":"形状",
"items":[
{
"title":"方形",
"flag":false,
"skuId":3
}
]
}
}
]
}
}
]
}
效果如图:
image

@转换成可以实现联动的数据格式,暂不考虑库存问题,不需没有的属性变灰,切换属性,其他属性变化,有属性就显示,无的话就不显示

@jinzhangcode
Copy link

function convert(list) {
let result = [];
let len = list.length;
function searchChild(parent){
if(!parent)return;
if(!parent.id){
for (let i = 0; i < len; i++) {
if(list[i].parentId == 0){
var item = list.splice(i,1)[0];
i--;
len--;
item.children =[];
parent.push(searchChild(item));
}
}
}else{
for (let i = 0; i < len; i++) {
if(parent.id == list[i].parentId){
var item = list.splice(i,1)[0];
i--;
len--;
item.children =[];
parent.children.push(searchChild(item))
}
}
}
return parent
}
searchChild(result);
return result;
}
let list =[
{id:1,name:'部门A',parentId:0},
{id:2,name:'部门B',parentId:0},
{id:3,name:'部门C',parentId:1},
{id:4,name:'部门D',parentId:1},
{id:5,name:'部门E',parentId:2},
{id:6,name:'部门F',parentId:3},
{id:7,name:'部门G',parentId:2},
{id:8,name:'部门H',parentId:4}
];
convert(list)

@wingmeng
Copy link

两轮遍历,时间复杂度 O(n^2) 😂

function convert(arr) {
  let tree = [];

  arr.map((it, idx, array) => {
    let parent = it.parentId;

    if (parent === 0) {  // 根节点        
      tree.push(it);
    } else {        
      array.map(item => {
        if (item.id === parent) {
          if (!item.children) {
            item.children = [];
          }

          item.children.push(it);
        }
      });
    }
  });

  return tree;
}

@wjryours
Copy link

let list = [
    { id: 1, name: '部门A', parentId: 0 },
    { id: 2, name: '部门B', parentId: 0 },
    { id: 3, name: '部门C', parentId: 1 },
    { id: 4, name: '部门D', parentId: 1 },
    { id: 5, name: '部门E', parentId: 2 },
    { id: 6, name: '部门F', parentId: 3 },
    { id: 7, name: '部门G', parentId: 2 },
    { id: 8, name: '部门H', parentId: 4 }
];
function convert(array) {
    let reslutArray = array.filter((item) => {
        let children = array.filter((child) => {
           return item.id === child.parentId
        })   
        item.children = children       
        return item.parentId === 0
    })
    return reslutArray
}
let res = convert(list)
console.log(res) 

@SpecializedM
Copy link

const convert = (list) => {
const result = [];

list.map(item => {
    if (item.parentId) {
        if (!list[item.parentId - 1]['children']) {
            list[item.parentId - 1]['children'] = [];
        }
        list[item.parentId - 1]['children'].push(item);
    }
    else {
        result.push(item)
    }
});

return result

}

@dbl520
Copy link

dbl520 commented Jun 12, 2019

两轮遍历,时间复杂度 O(n^2) 😂

function convert(arr) {
  let tree = [];

  arr.map((it, idx, array) => {
    let parent = it.parentId;

    if (parent === 0) {  // 根节点        
      tree.push(it);
    } else {        
      array.map(item => {
        if (item.id === parent) {
          if (!item.children) {
            item.children = [];
          }

          item.children.push(it);
        }
      });
    }
  });

  return tree;
}

大佬看看我的?

@zhaoshaobang
Copy link

function convert(list) {
    var obj = {};
    var result = [];
    list.map(el => {
        obj[el.id] = el;
    })
    for(let i=0, len = list.length; i < len; i++) {
        let id = list[i].parentId;
        if(id == 0) {
            result.push(list[i]);
            continue;
        }
        if(obj[id].children) {
            obj[id].children.push(list[i]);
        } else {
            obj[id].children = [];
            obj[id].children.push(list[i]);
        }
    }
    return result;
}

let list = [
    { id: 1, name: '部门A', parentId: 0 },
    { id: 2, name: '部门B', parentId: 0 },
    { id: 3, name: '部门C', parentId: 1 },
    { id: 4, name: '部门D', parentId: 1 },
    { id: 5, name: '部门E', parentId: 2 },
    { id: 6, name: '部门F', parentId: 3 },
    { id: 7, name: '部门G', parentId: 2 },
    { id: 8, name: '部门H', parentId: 4 }
];

convert(list);

@NewPrototype
Copy link

@

function  convert(list){
	 const  res  = []
	 const  map  =  list。减少((RES,v)=>(RES [ v。ID ] = V,RES),{}
	 为(const的 项目 的列表){
		 如果(项目。parentId的 ===  0{
			 水库。推(项目)
			 继续
		}
		如果(项目。parentId的 在地图){
			 const的  =地图[ 项目。parentId ]
			 父母。孩子 =  父母。孩子们 || []
			 父母。孩子们。推(项目)
		}
	}
	返回资源
}

时间复杂度为O(n)

这个算不上O(n)吧

@NewPrototype
Copy link

NewPrototype commented Jun 12, 2019

const convert = (list) => {
  if (!Array.isArray(list)) {
    return []
  }
  list.forEach((v) => {
    const index = list.findIndex((_l) => {
      return v.parentId == _l.id
    });
    if (index == -1) {
      return
    }
    list[index].child = list[index].child || []
    list[index].child.push(v);
    v.hide = true;
  });
  return list.filter(v => { return !v.hide });
}

难度的话O(n*2)左右

@ZodiacSyndicate
Copy link

@

function  convert(list){
	 const  res  = []
	 const  map  =  list。减少((RES,v)=>(RES [ v。ID ] = V,RES),{}
	 为(const的 项目 的列表){
		 如果(项目。parentId的 ===  0{
			 水库。推(项目)
			 继续
		}
		如果(项目。parentId的 在地图){
			 const的  =地图[ 项目。parentId ]
			 父母。孩子 =  父母。孩子们 || []
			 父母。孩子们。推(项目)
		}
	}
	返回资源
}

时间复杂度为O(n)

这个算不上O(n)吧

这就是O(n)啊, 第一次遍历生成哈希表扫描了一次,然后再扫描了一次list,总共进行了2n次操作,时间复杂度是O(2n) = O(n)

@NewPrototype
Copy link

function convert(list) {
	const res = []
	const map = list.reduce((res, v) => (res[v.id] = v, res), {})
	for (const item of list) {
		if (item.parentId === 0) {
			res.push(item)
			continue
		}
		if (item.parentId in map) {
			const parent = map[item.parentId]
			parent.children = parent.children || []
			parent.children.push(item)
		}
	}
	return res
}

时间复杂度O(n)
执行了一次map,一次for,应该是o(n^2)了吧

@teachat8
Copy link

基于DFS来写

function convert(source, parentId = 0){
    let trees = [];
    for (let item of source) {
      if(item.parentId === parentId) {
        let children = convert(source, item['id']);
        if(children.length) {
          item.children = children
        }
        trees.push(item);
      }
    }
    return trees;
  }

let list =[
    {id:1,name:'部门A',parentId:0},
    {id:2,name:'部门B',parentId:0},
    {id:3,name:'部门C',parentId:1},
    {id:4,name:'部门D',parentId:1},
    {id:5,name:'部门E',parentId:2},
    {id:6,name:'部门F',parentId:3},
    {id:7,name:'部门G',parentId:2},
    {id:8,name:'部门H',parentId:4}
];

const result = convert(list);

@lwwen
Copy link

lwwen commented Jun 12, 2019

function convert(list){
let map={};
let newArr=[];
for(var i=0;i<list.length;i++){
map[list[i].id]=list[i]
}
for(var i=0;i<list.length;i++){
if(list[i].parentId in map){
map[list[i].parentId].children=[];
map[list[i].parentId].children.push(list[i])
}
if(map[list[i].parentId] && 'children' in map[list[i].parentId]){
newArr.push(map[list[i].parentId])
}
}
return newArr
}

@ZodiacSyndicate
Copy link

function convert(list) {
	const res = []
	const map = list.reduce((res, v) => (res[v.id] = v, res), {})
	for (const item of list) {
		if (item.parentId === 0) {
			res.push(item)
			continue
		}
		if (item.parentId in map) {
			const parent = map[item.parentId]
			parent.children = parent.children || []
			parent.children.push(item)
		}
	}
	return res
}

时间复杂度O(n)
执行了一次map,一次for,应该是o(n^2)了吧

如果这两个是嵌套循环就是n^2, 代码里面明显是两次,而不是嵌套的

@NewPrototype
Copy link

function convert(list) {
	const res = []
	const map = list.reduce((res, v) => (res[v.id] = v, res), {})
	for (const item of list) {
		if (item.parentId === 0) {
			res.push(item)
			continue
		}
		if (item.parentId in map) {
			const parent = map[item.parentId]
			parent.children = parent.children || []
			parent.children.push(item)
		}
	}
	return res
}

时间复杂度O(n)
执行了一次map,一次for,应该是o(n^2)了吧

如果这两个是嵌套循环就是n^2, 代码里面明显是两次,而不是嵌套的

for of里面不是包括了for in 吗?

@ZodiacSyndicate
Copy link

function convert(list) {
	const res = []
	const map = list.reduce((res, v) => (res[v.id] = v, res), {})
	for (const item of list) {
		if (item.parentId === 0) {
			res.push(item)
			continue
		}
		if (item.parentId in map) {
			const parent = map[item.parentId]
			parent.children = parent.children || []
			parent.children.push(item)
		}
	}
	return res
}

时间复杂度O(n)
执行了一次map,一次for,应该是o(n^2)了吧

如果这两个是嵌套循环就是n^2, 代码里面明显是两次,而不是嵌套的

for of里面不是包括了for in 吗?
哪有for in,item.parantId in map,在一个对象里面查找一个key是O(1)的操作

@lhyt
Copy link

lhyt commented Jun 12, 2019

一次循环解决

function convert(list) {
	const cache = new Map()
	return list.reduce((res, cur) => {
		const { id, parentId } = cur
		const item = { ...cur }
		if (parentId === 0) {
			res.push(item)
		} else {
			const itemCache = cache.get(parentId)
			!itemCache.children && (itemCache.children = [])
			itemCache.children.push(item)
		}
		cache.set(id, item)
		return res
	}, []);
}

@NewPrototype
Copy link

function convert(list) {
	const res = []
	const map = list.reduce((res, v) => (res[v.id] = v, res), {})
	for (const item of list) {
		if (item.parentId === 0) {
			res.push(item)
			continue
		}
		if (item.parentId in map) {
			const parent = map[item.parentId]
			parent.children = parent.children || []
			parent.children.push(item)
		}
	}
	return res
}

时间复杂度O(n)
执行了一次map,一次for,应该是o(n^2)了吧

如果这两个是嵌套循环就是n^2, 代码里面明显是两次,而不是嵌套的

for of里面不是包括了for in 吗?
哪有for in,item.parantId in map,在一个对象里面查找一个key是O(1)的操作
这个map看错了,哈哈哈

@LqqJohnny
Copy link

用递归试试

function convert(array , parentId=0){
  let result = []
  array.forEach((item,index)=>{
    if(item.parentId === parentId){
      let children = convert(array,item.id);
      if(children.length>0){
        item.children = children ;
      }
      result.push(item);
    }
  })
  return result;
}

@foolmadao
Copy link

covert(lists: any[]): any[] {
    const findItem = (id: number) => {
      return lists.find(item => item.id === id);
    };
    const result = [];
    lists.map(item => {
      if (item.parentId === 0) {
        result.push(item);
      } else {
        const target = findItem(item.parentId);
        target.children = target.children || [];
        target.children.push(item);
      }
    });
    return result;
  }

看了大佬们写的用map要好一些

@yeyan1996
Copy link

function convert(list) {
    let m = new Map()
    return list.reduce((pre,cur)=>{
        m.set(cur.id,cur)
        let parent = m.get(cur.parentId)
        if( parent){
            (parent.children || (parent.children = [])).push(cur)
            return pre
        }
      return [...pre,cur]
    },[])
}

这么多人写了我就随便再写个吧,时间复杂度 O(n)

@GuoYuFu123
Copy link

/*
转换成树形结构
思路:
1、构造一个id与对象的对应关系
2、循环变价原数组,将item放在指定的parent之下
3、循环字典,找出parentId === 0的对象即可
****一共3遍遍历3*O(n)*****
*/
function convert (list) {

    let arr = [];
    let dict = {};
    list.forEach(item => {
        dict[item.id] = item;
    })
    list.forEach(item => {
        if(item.parentId) {
            let children = dict[item.parentId].children;
            if (children) {
                dict[item.parentId].children.push(item)
            } else {
                dict[item.parentId].children = [item];
            }
        } 
    }) 
    for(let key in dict) {
        if(dict[key].parentId === 0) {
            arr.push(dict[key])
        }
    }
    return arr;
}
let list =[
    {id:1,name:'部门A',parentId:0},
    {id:2,name:'部门B',parentId:0},
    {id:3,name:'部门C',parentId:1},
    {id:4,name:'部门D',parentId:1},
    {id:5,name:'部门E',parentId:2},
    {id:6,name:'部门F',parentId:3},
    {id:7,name:'部门G',parentId:2},
    {id:8,name:'部门H',parentId:4}
];
let res = convert(list);
console.log(res)

@dbl520
Copy link

dbl520 commented Jun 14, 2019

有大佬看看我的吗

@k-0311
Copy link

k-0311 commented Jun 24, 2019

const convert = (list) => {
    const obj = {}
    while (list.length) {
      let temp = list.shift()
      obj[temp.id] = temp
      if(obj[temp.parentId]) {
        obj[temp.parentId]['children'] = (obj[temp.parentId]['children'] || []).concat(temp)
      }
    }
    return [...Object.values(obj)].filter(item => item.parentId === 0)
  }
  const res = convert(list)

@pengcc
Copy link

pengcc commented Jul 8, 2019

加了个map记录parent的路径,这个循环一次。

const convertData2Tree = (dataArr) => {
    let nodesMap = {};
    let result = [];
    dataArr.forEach(element => {
        let { id, parentId } = element;
        if (parentId === 0) {
            result.push(element);
            nodesMap[id] = result[result.length - 1];
        } else {
            let parent = nodesMap[parentId];
            if (!parent.children) {
                parent.children = [];
            }
            parent.children.push(element);
            nodesMap[id] = nodesMap[parentId].children[parent.children.length - 1];
        }
    });
    return result;
};

@kaierrao
Copy link

image

这句没看懂,具体什么意思能说一下吗?

@chphaeton
Copy link

function convert(list) {
	const res = []
	const map = list.reduce((res, v) => (res[v.id] = v, res), {})
	for (const item of list) {
		if (item.parentId === 0) {
			res.push(item)
			continue
		}
		if (item.parentId in map) {
			const parent = map[item.parentId]
			parent.children = parent.children || []
			parent.children.push(item)
		}
	}
	return res
}

时间复杂度O(n)

这个的时间复杂度为什么不是2*O(n)

@lpdong
Copy link

lpdong commented Mar 21, 2021

 function convert(list) {
      const map = {};
      const res = [];
      list.forEach((item) => {
        const obj = {
          id: item.id,
          name: item.name,
          parentId: 0,
        };
        if (map[item.id]) { // 之前简单生成的数据没有name和parentId,此时添加上
          map[item.id].name = item.name;
          map[item.id].parentId = item.parentId;
        } else {
          map[item.id] = obj;
        }
        if (item.parentId === 0) {
          res.push(map[item.id]);
        } else {
          if (map[item.parentId]) {
            map[item.parentId].children = map[item.parentId].children
              ? map[item.parentId].children.concat(map[item.id])
              : [map[item.id]];
          } else {
            // 如果此时对于的parentId部门在map中没有对于值,先简单生成
            map[item.parentId] = {
              id: item.parentId,
              children: [map[item.id]],
            };
          }
        }
      });
      return res;
    }

O(n)时间复杂度,边遍历编生成map,可以处理顺序不对的情况

const list = [
      { id: 3, name: '部门C', parentId: 1 },  // 此时部门1还没有生成,
      { id: 1, name: '部门A', parentId: 0 },
      { id: 2, name: '部门B', parentId: 0 },
      { id: 4, name: '部门D', parentId: 1 },
      { id: 5, name: '部门E', parentId: 2 },
      { id: 6, name: '部门F', parentId: 3 },
      { id: 7, name: '部门G', parentId: 2 },
      { id: 8, name: '部门H', parentId: 4 },
    ];

@XW666
Copy link

XW666 commented Mar 25, 2021

//方式一
 function convert(arr) {
    let map = {}, list = []
    arr.forEach(item => {
      map[item.id] = item
    });
    for (let item of arr) {
      if (item.parentId === 0) {
        list.push(item)
      } else {
        if (map[item.parentId]) {
          const parent = map[item.parentId]
          parent.children = parent.children || []
          parent.children.push(item)
        }
      }

    }
    return list;
  }
//方式二
 const handleTree = (arr) => {
    //存储parentId值相同的子集
    var childrenListMap = {};
    //存储当前所有id 集合
    var nodeIds = {};
    //树形结构
    var tree = [];
    for (let c of arr) {
      let parentId = c.parentId
      if (!childrenListMap[parentId]) {
        childrenListMap[parentId] = []
      }
      nodeIds[c.id] = c
      childrenListMap[parentId].push(c)
    }
    for (let c of arr) {
      let parentId = c.parentId
      if (!nodeIds[parentId]) {
        tree.push(c)
      }
    }

    for (let c of tree) {
      getChlien(c)
    }
    //递归
    function getChlien(c) {
      if (childrenListMap[c.id]) {
        c.children = childrenListMap[c.id]
      }
      if (c.children) {
        for (let s of c.children) {
          getChlien(s);
        }
      }
    }

  }

@daisybaicai
Copy link

function convert(data) {
  const idMapping = data.reduce((acc, cur, index) => {
    acc[cur.id] = index
    return acc
  }, {})
  const arr = []
  data.forEach(el => {
    if (el.parentId === 0) {
      arr.push(el)
      return
    }
    const parentEl = data[idMapping[el.parentId]]
    parentEl.children = [...(parentEl.children || []), el]
  })
  return arr
}

@xiangergou
Copy link

  const listToTree = (tree) => {
    const map = tree.reduce((map, crt) => (map[crt.id] = crt, crt.children = [], map), {})
    return tree.filter(node => {
      node.parentId && map[node.parentId].children.push(node)
      return !node.parentId
    })
  }

@zhelingwang
Copy link

let list = [
  { id: 1, name: '部门A', parentId: 0 },
  { id: 2, name: '部门B', parentId: 0 },
  { id: 3, name: '部门C', parentId: 1 },
  { id: 4, name: '部门D', parentId: 1 },
  { id: 5, name: '部门E', parentId: 2 },
  { id: 6, name: '部门F', parentId: 3 },
  { id: 7, name: '部门G', parentId: 2 },
  { id: 8, name: '部门H', parentId: 4 },
  { id: 9, name: '部门I', parentId: 10 },
];
const result = convert(list);

function convert(list) {
  list = list.sort((a, b) => a.parentId - b.parentId);
  let i = list.length - 1;
  while (i > 0) {
    const item = list[i];
    const parent = list.find(itm => itm.id === item.parentId);
    if (parent) {
      parent.children = parent.children || [];
      parent.children.push(item);
      list.splice(i, 1);
    }
    i--;
  }
  return list;
}

console.log(result);

@zengkan0703
Copy link

一次遍历搞定

function convert(list) {
  const root = {
    children: []
  };
  const map = {
    0: root
  };
  for (let item of list) {
    const { id, name, parentId } = item;
    const current = map[id] || (map[id] = {
      children: []
    })
    current.id = id;
    current.name = name;
    const parent = map[parentId] || (map[parentId] = {
      children: []
    })
    parent.children.push(current);
  }
  return root.children;
}

@wangliang1124
Copy link

wangliang1124 commented May 26, 2021 via email

@wmb0412
Copy link

wmb0412 commented Jun 10, 2021

const convert=(list)=>{
	const map={};
	const result=[];
	for (let index = 0; index < list.length; index++) {
		map[list[index].id]=list[index]
		
	}
	for (let index = 0; index < list.length; index++) {
		const element = list[index];
		if(element.parentId==0){
			result.push(element)
		}else{
			if(element.parentId in map){
				if(map[element.parentId].children){
					map[element.parentId].children.push(element)
				}else{
					map[element.parentId].children=[element]
				}
			}
		}
	}
	return result
}

@Soyn
Copy link

Soyn commented Aug 4, 2021

/**
 * record := {}
 * i := 0
 * while i < list.length
 *    if record[list[i].parentId] == null
 *       record[list[i].parentId] := [];
 *    end if
 *    record[list[i].parentId].push(list[i]);
 *    i += 1
 * i := 0
 * res := []
 * while i < list.length
 *  treeNode := list[i]
 *  if treeNode.parentId === 0
 *     res.push(treeNode)
 *  end if
 *  children := record[treeNode.id] || []
 *  treeNode.children = children
 *  i += 1
 * return res
 */

const solution = (list) => {
  const record = list.reduce((res, node, idx) => {
    if (!res[node.parentId]) res[node.parentId] = [];
    res[node.parentId].push(list[idx]);
    return res;
  }, {});
  let res = [];
  list.forEach((ele) => {
    const treeNode = ele;
    if (treeNode.parentId === 0) res.push(treeNode);
    treeNode.children = record[treeNode.id] || [];
  });
  return res;
};

let list = [
  { id: 1, name: "部门A", parentId: 0 },
  { id: 2, name: "部门B", parentId: 0 },
  { id: 3, name: "部门C", parentId: 1 },
  { id: 4, name: "部门D", parentId: 1 },
  { id: 5, name: "部门E", parentId: 2 },
  { id: 6, name: "部门F", parentId: 3 },
  { id: 7, name: "部门G", parentId: 2 },
  { id: 8, name: "部门H", parentId: 4 }
];

solution(list);

@zjt-dev
Copy link

zjt-dev commented Sep 8, 2021

const convert = list => {
	for (let i = 0, length = list.length; i < length; i++) {
		const el = list[i];
		el.children = el.children || [];
		let index = list.findIndex(v => v.id == el.parentId);
		if (index !== -1) {
			list[index].children.push(el);
		}
	}
	return list.filter(v => v.parentId == 0);
};

这样有什么问题吗

@Tarkpak
Copy link

Tarkpak commented Sep 9, 2021

function convert(list) {
	const res = []
	const map = list.reduce((res, v) => (res[v.id] = v, res), {})
	for (const item of list) {
		if (item.parentId === 0) {
			res.push(item)
			continue
		}
		if (item.parentId in map) {
			const parent = map[item.parentId]
			parent.children = parent.children || []
			parent.children.push(item)
		}
	}
	return res
}

时间复杂度O(n)

这样好像会影响到原 list,最好在 convert 方法中深拷贝一下(个人用的是 JSON.parse(JSON.stringify(source.list))

@zhangtaolei
Copy link

zhangtaolei commented Nov 22, 2021

dfs

function convert(arr,parentId = 0){
  let tree = []
  for(let i in arr){
    if(arr[i].parentId === parentId){
      let children = convert(arr,arr[i].id)
      if(children.length){
        arr[i].children = convert(arr,arr[i].id)
      }
      tree.push(arr[i])
    }
  }
  return tree
}

@WebXiaoMing
Copy link

let list = [
  {id: 1, name: '部门A', parentId: 0 },
  {id:2,name:'部门B',parentId:0},
  {id:3,name:'部门C',parentId:1},
  {id:4,name:'部门D',parentId:1},
  {id:5,name:'部门E',parentId:2},
  {id:6,name:'部门F',parentId:3},
  {id:7,name:'部门G',parentId:2},
  {id:8,name:'部门H',parentId:4}
];

function convert(list, rootId) {
  return list.reduce((res, curr) => {
    if (curr.parentId === rootId) {
      curr.children = convert(list.filter(item => item.parentId !== rootId), curr.id)
      res.push(curr)
    }
    return res
  }, [])
}

console.log(convert(list, 0))

@SnailOwO
Copy link

 let list = [{
        id: 1,
        name: '部门A',
        parentId: 0
    }, {
        id: 2,
        name: '部门B',
        parentId: 0
    }, {
        id: 3,
        name: '部门C',
        parentId: 1
    }, {
        id: 4,
        name: '部门D',
        parentId: 1
    }, {
        id: 5,
        name: '部门E',
        parentId: 2
    }, {
        id: 6,
        name: '部门F',
        parentId: 3
    }, {
        id: 7,
        name: '部门G',
        parentId: 2
    }, {
        id: 8,
        name: '部门H',
        parentId: 4
    }];

    function convert(list = []) {
        if (list.length) {
            const res = {}
            for (const val of list) {
                if (!res[val.id]) {
                    res[val.id] = val
                }
                if (res[val.parentId]) {
                    if (!res[val.parentId].children) {
                        res[val.parentId].children = []
                    }
                    res[val.parentId].children.push(val)
                }
            }
            return res
        }
    }
    console.log(convert(list));

@ChaoyanWu97
Copy link

function convert(list) {
	const res = []
	const map = list.reduce((res, v) => (res[v.id] = v, res), {})
	for (const item of list) {
		if (item.parentId === 0) {
			res.push(item)
			continue
		}
		if (item.parentId in map) {
			const parent = map[item.parentId]
			parent.children = parent.children || []
			parent.children.push(item)
		}
	}
	return res
}

时间复杂度O(n)

如果list的数据是这样的,就得不到正确结果了

 let list =[
        {id:4,name:'部门D',parentId:1},
        {id:5,name:'部门E',parentId:2},
        {id:6,name:'部门F',parentId:3},
        {id:7,name:'部门G',parentId:2},
        {id:1,name:'部门A',parentId:0},
        {id:2,name:'部门B',parentId:0},
        {id:3,name:'部门C',parentId:1},
        {id:8,name:'部门H',parentId:4}
    ];

@cmw-big
Copy link

cmw-big commented Mar 3, 2022

interface Department {
  id: number
  name: string
  parentId: number
}

interface TreeDepartment {
  id: number
  name: string
  parentId: number
  children?: TreeDepartment[]
}

function convert(list: Department[]): TreeDepartment[] {
  const result: TreeDepartment[] = []
  const idMap = new Map<number, TreeDepartment>()
  list.forEach(item => {
    const node = idMap.get(item.id)
    const nodeChildren = node?.children
    const params: TreeDepartment = { ...item }
    if (nodeChildren) {
      params.children = nodeChildren
    }
    idMap.set(item.id, params)
    if (item.parentId === 0) {
      result.push(params)
      return
    }
    const parentNode = idMap.get(item.parentId)
    if (parentNode) {
      parentNode.children
        ? parentNode.children.push(params)
        : (parentNode.children = [params])
    } else {
      idMap.set(item.parentId, {
        children: [params]
      } as TreeDepartment)
    }
  })
  return result
}

const list = [
  { id: 1, name: '部门A', parentId: 0 },
  { id: 2, name: '部门B', parentId: 0 },
  { id: 3, name: '部门C', parentId: 1 },
  { id: 4, name: '部门D', parentId: 1 },
  { id: 5, name: '部门E', parentId: 2 },
  { id: 6, name: '部门F', parentId: 3 },
  { id: 7, name: '部门G', parentId: 2 },
  { id: 8, name: '部门H', parentId: 4 }
]
const result = convert(list)
console.dir(result, { depth: null })

@Shijiuwei
Copy link

let list = [
  {id: 1, name: '部门A', parentId: 0 },
  {id:2,name:'部门B',parentId:0},
  {id:3,name:'部门C',parentId:1},
  {id:4,name:'部门D',parentId:1},
  {id:5,name:'部门E',parentId:2},
  {id:6,name:'部门F',parentId:3},
  {id:7,name:'部门G',parentId:2},
  {id:8,name:'部门H',parentId:4}
];

function convert(list) {
  let result = {};
  const root = 0;

  list.forEach((item) => {
    const { id, parentId } = item;
    if (result[id]) {
      result[id] = { ...result[id], ...item };
    } else {
      result[id] = { ...item, child: [] };
    }

    const parent = parentId
    if (result[parent]) {
      result[parent].child.push(result[id]);
    } else {
      result[parent] = { id: parent, child: [result[id]] };
    }
  });

  return result[root].child;
}

console.log(convert(list));

时间复杂度: O(n);

@Owen-MS
Copy link

Owen-MS commented Apr 14, 2022

function convert(list) {
  const map = new Map(); // 借用对象内存指针指向堆
  return list.reduce((pre, cur) => {
    const { id, parentId } = cur;
    if (parentId === 0) {
      pre.push(cur);
    } else {
      const itemCache = map.get(parentId);
      if (itemCache) {
        itemCache.children = itemCache.children ? [...itemCache.children, cur] : [cur];
      }
    }
    if (!map.has(id)) {
      map.set(id, cur);
    }
    return pre;
  }, []);
}

@AKclown
Copy link

AKclown commented Jun 13, 2022

function convert(list, pid) {
function tree(id) {
return list.filter(item =>
item.parentId === id
).map(i => ({
id: i.id,
name: i.name,
parentId: i.parentId,
children: tree(i.id)
}))
}
return tree(pid);
}
const result = convert(list, 0);

@guzao
Copy link

guzao commented Jul 11, 2022

export function flatArrToTree (arr: Array<object>): Array<any> {
  // 建立关系表
  const map = createCorrelationMap(arr)
  // 生成树形结构
  const result = createTree(arr, map)

  return result
}

function createCorrelationMap (arr: Array<object>): object {
  // 建立关系表
  const map = {}
  arr.forEach((item: any) => {
    map[item.id] = item
    map[item.id].children = []
  })
  return map
}

function createTree (arr: Array<object>, map: object): Array<any> {
  const result = []
  arr.forEach((item: any) => {
    if (item.pid == 0) {
      // pid 为零直接作为根节点
      result.push(item)
    } else {
      // 不为零查询当前数据的父节点
      const paraent = map[item.pid]
      paraent.children.push(item)
    }
  })
  return result
}

@IveChen
Copy link

IveChen commented Oct 11, 2022 via email

@caroundsky
Copy link

function converTree(arr) {
    const tree = []
    const treeMap = {}
    while(arr.length) {
        const target = arr.shift()
        treeMap[target.id] = target
        
        if (target.parentId === 0) {
            tree.push(target)
            continue
        }
        
        if (treeMap[target.parentId]) {
            (treeMap[target.parentId].children || (treeMap[target.parentId].children = [])).push(target)
        }
    }
    return tree
}

@benzhemin
Copy link

benzhemin commented Feb 25, 2023

const treeOrganization = orgList => {

    const treeList = [];

    for (const org of orgList) {
        if (!recursiveTraverse(treeList, findInsertFn(org))) {
            org.children = [];
            treeList.push(org);
        }
    }

    return treeList;
}

const findInsertFn = current => node => {
    if (node.id === current.parentId) {
        current.children = [];
        node.children = [...node.children, current];
        return true;
    }
    return false;
}

const recursiveTraverse = (nodeList, findCallback) => {
    for (const node of nodeList) {
        if (findCallback(node)) {
            return true;
        }

        if (recursiveTraverse(node.children, findCallback)) {
            return true;
        }
    }

    return false;
}

let orgList =[
    {id:1,name:'部门A',parentId:0},
    {id:2,name:'部门B',parentId:0},
    {id:3,name:'部门C',parentId:1},
    {id:4,name:'部门D',parentId:1},
    {id:5,name:'部门E',parentId:2},
    {id:6,name:'部门F',parentId:3},
    {id:7,name:'部门G',parentId:2},
    {id:8,name:'部门H',parentId:4}
];

const treeList = treeOrganization(orgList);

console.log(JSON.stringify(treeList, null, 2));

@jayguojianhai
Copy link

jayguojianhai commented Mar 22, 2023

function convert (arr) { var map = {}; var res = []; arr.forEach(o => map[o.id] = o); arr.forEach(o => { var parent = map[o.parentId]; if (parent) { (parent.children || (parent.children = [])).push(o); } else { res.push(o); } }); return res; }

@cxl-blog
Copy link

function convert2(arr: Item[]): TreeItem[] {
  let res: TreeItem[] = [];

  let itemMap: NonNullable<{ [key: number]: Partial<TreeItem> }> = {};

  for (const item of arr) {
    const { id, parentId } = item;

    if (!itemMap[id]) {
      itemMap[id] = {
        children: [],
      };
    }

    // 避免临时创建的父节点没有其他完整信息
    itemMap[id] = {
      ...item,
      children: itemMap[id].children,
    };

    const treeItem = itemMap[id];

    if (parentId === 0) {
      res.push(treeItem as TreeItem);
    } else {
      if (!itemMap[parentId]) {
        itemMap[parentId] = {
          children: [],
        };
      } else {
        itemMap[parentId].children?.push(treeItem as TreeItem);
      }
    }
  }

  return res;
}

// O(n)

@aksaber
Copy link

aksaber commented Apr 6, 2023

function convert(list) {
let obj = {}
list.forEach(item => {
obj[item.id] = item
})
const result = list.filter(item => {
if (obj[item.parentId]) {
obj[item.parentId].children?.push(item) || (obj[item.parentId].children = [item])
}
return item.parentId === 0
})
return result
}
const result = convert(list)

@1242793152
Copy link

提供俩种写法,欢迎大家来看
let list =[
{id:1,name:'部门A',parentId:0},
{id:2,name:'部门B',parentId:0},
{id:3,name:'部门C',parentId:1},
{id:4,name:'部门D',parentId:1},
{id:5,name:'部门E',parentId:2},
{id:6,name:'部门F',parentId:3},
{id:7,name:'部门G',parentId:2},
{id:8,name:'部门H',parentId:4}
];
function convert1(arr){
let result = []
let obj = arr.reduce((pre,cur)=>{
pre[cur.id] = cur
pre[cur.id].children = []
return pre
},{})
for(let item of list){
const {id,parentId} = item
if(parentId === 0 ){
result.push(obj[id])
}else{
obj[parentId] != undefined ? obj[parentId].children.push(item) : ''
}
}
return result
}
console.log(convert1(list))

function convert2(arr){
let result = []
let obj = {}
for(let item of arr){
const {id,parentId} = item
obj[id] === undefined ? obj[id] = {children:[]} : ''
obj[id] = {
...item,
children:obj[id].children
}
if(parentId === 0){
result.push(obj[id])
}else{
if(obj[parentId] === undefined){
obj[parentId].children = []
}
obj[parentId].children.push(obj[id])
}
}
return result
}
console.log(convert2(list))

@zengjie3154
Copy link

function convert(list) {
	const res = []
	const map = list.reduce((res, v) => (res[v.id] = v, res), {})
	for (const item of list) {
		if (item.parentId === 0) {
			res.push(item)
			continue
		}
		if (item.parentId in map) {
			const parent = map[item.parentId]
			parent.children = parent.children || []
			parent.children.push(item)
		}
	}
	return res
}

时间复杂度O(n)

如果有断层或者不规律的数据会有遗漏

const list=[
{id:1,name:'部门A',parentId:0},
{id:2,name:'部门B',parentId:0},
{id:3,name:'部门C',parentId:1},
{id:4,name:'部门D',parentId:1},
{id:5,name:'部门E',parentId:2},
{id:6,name:'部门F',parentId:3},
{id:7,name:'部门G',parentId:2},
{id:8,name:'部门H',parentId:4},
{id:12,name:'部门K,parentId:9}
];
const convert = (list)=>{
let res = []
let map = list.sort((a, b) => b.id - a.id)
for (const item of map) {
const arr = map.filter(v => v.parentId === item.id)
if (arr.length) {
item.children = arr
res = res.filter(v => v.parentId !== item.id)
}
res.push(item)
}
return res
}
convert(list)

@chthu
Copy link

chthu commented Apr 13, 2023

const arrToTree = (list: any) => {
const result: any = []
const map: any = {}
for (const item of list) {
const { id, parentId: pid } = item
if (!map[id]) {
map[id] = { children: [] }
}
map[id] = { ...item, children: map[id].children }
const tree = map[id]
if (pid === 0) {
result.push(tree)
} else {
if (!map[pid]) {
map[pid] = { children: [] }
}
map[pid].children.push(tree)
}
}
return result
}

@negativeentropy9
Copy link

function convert(arr) {
  const map = {};
  const result = [];

  for (let item of arr) {
    const { id, parentId, name } = item;

    if (map[id]) {
      map[id].name = name;
      map[id].parentId = parentId;
    } else {
      map[id] = Object.assign({ children: [] }, item);
    }

    if (parentId === 0) {
      result.push(map[id]);
    } else {
      if (map[parentId]) {
        map[parentId].children.push(map[id]);
      } else {
        map[parentId] = {
          id: parentId,
          children: [map[id]],
        };
      }
    }
  }

  return result;
}

console.log(
  convert([
    { id: 1, name: "部门A", parentId: 0 },
    { id: 2, name: "部门B", parentId: 0 },
    { id: 3, name: "部门C", parentId: 1 },
    { id: 4, name: "部门D", parentId: 1 },
    { id: 5, name: "部门E", parentId: 2 },
    { id: 6, name: "部门F", parentId: 3 },
    { id: 7, name: "部门G", parentId: 2 },
    { id: 8, name: "部门H", parentId: 4 },
  ])
);

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

No branches or pull requests