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

第 125 题:如何将 [{id: 1}, {id: 2, pId: 1}, ...] 的重复数组(有重复数据)转成树形结构的数组 [{id: 1, child: [{id: 2, pId: 1}]}, ...] (需要去重) #243

Open
yygmind opened this issue Aug 13, 2019 · 32 comments

Comments

@yygmind
Copy link
Contributor

yygmind commented Aug 13, 2019

No description provided.

@yygmind yygmind changed the title 第 125 题:如何将[{id: 1}, {id: 2, pId: 1}, ...] 的重复数组(有重复数据)转成树形结构的数组 [{id: 1, child: [{id: 2, pId: 1}]}, ...] (需要去重) 第 125 题:如何将 [{id: 1}, {id: 2, pId: 1}, ...] 的重复数组(有重复数据)转成树形结构的数组 [{id: 1, child: [{id: 2, pId: 1}]}, ...] (需要去重) Aug 13, 2019
@ZodiacSyndicate
Copy link

哈希表,时间复杂度O(n)

const fn = arr => {
  const res = []
  const map = arr.reduce((res, item) => ((res[item.id] = item), res), {})
  for (const item of Object.values(map)) {
    if (!item.pId) {
      res.push(item)
    } else {
      const parent = map[item.pId]
      parent.child = parent.child || []
      parent.child.push(item)
    }
  }
  return res
}

// const arr = [{id: 1}, {id:2, pId: 1}, {id: 3, pId: 2}, {id: 4}, {id:3, pId: 2}, {id: 5, pId: 4}]
// fn(arr) => [{id: 1, child: [{id: 2, pId: 1, child: [{ id: 3, pId: 2}]}]}, {id: 4, child: [{id: 5, pId: 4}]}]

@weiweixuan
Copy link

是这个意思吗,不太清楚,轻喷哈

 //    如何将 [{id: 1}, {id: 2, pId: 1}, ...] 的重复数组(有重复数据)转成树形结构的数组 [{id: 1, child: [{id: 2, pId: 1}]}, ...] (需要去重)
      let arr = [
        { id: 1 },
        { id: 2, pid: 1 },
        { id: 3, pid: 2 },
        { id: 4, pid: 1 },
        { id: 5, pid: 3 },
        { id: 6, pid: 2 },
        { id: 6, pid: 2 },
        { id: 2, pid: 1 }
      ]
      function changeSet(arr) {
        let flatArr = [...new Set(arr.map(item => JSON.stringify(item)))].map(
          item => JSON.parse(item)
        )
        let res = flatArr.reduce((prev, item) => {
          if (item.pid) {
            let father = flatArr.find(cur => cur.id == item.pid)
            father.child ? father.child.push(item) : (father.child = [item])
            return prev
          } else {
            return (item.child = []), prev.push(item), prev
          }
        }, [])
      }
      let res = changeSet(arr)
      console.log(res)

@JaniceDong
Copy link

JaniceDong commented Aug 13, 2019

var flatLs = [
{ id: 1},
{ id: 2},
{ id: 3},
{ id: 4, pid: 1 },
{ id: 5, pid: 3 },
{ id: 6, pid: 2 },
{ id: 7, pid: 4 },
{ id: 8, pid: 3 },
{ id: 9, pid: 4 }
]
const flat2tree = flatLs => {
flatLs.forEach(item => {
if (!item.pid) {
item.pid = 0;
} else {
const index = flatLs.findIndex(_item => _item.id === item.pid)
if (index !== -1) {
flatLs[index].children = flatLs[index].children || []
flatLs[index].children.push(item)
}
}
})
return flatLs.filter(item => item.pid === 0)
}
为什么代码没有缩进,[笑哭]

@McCarthey
Copy link

哈希表,时间复杂度O(n)

const fn = arr => {
  const res = []
  const map = arr.reduce((res, item) => ((res[item.id] = item), res), {})
  for (const item of Object.values(map)) {
    if (!item.pId) {
      res.push(item)
    } else {
      const parent = map[item.pId]
      parent.child = parent.child || []
      parent.child.push(item)
    }
  }
  return res
}

// const arr = [{id: 1}, {id:2, pId: 1}, {id: 3, pId: 2}, {id: 4}, {id:3, pId: 2}, {id: 5, pId: 4}]
// fn(arr) => [{id: 1, child: [{id: 2, pId: 1, child: [{ id: 3, pId: 2}]}]}, {id: 4, child: [{id: 5, pId: 4}]}]

@ZodiacSyndicate 👍 厉害!(提个小建议,最好复制一下对象,否则会修改原数组)

const map = arr.reduce((res, item) => ((res[item.id] = Object.assign({}, item)), res), {})

@GitHubJiKe
Copy link

const arr = [
  { id: 1, pid: null },
  { id: 2, pid: 1 },
  { id: 3, pid: 1 },
  { id: 4, pid: 2 },
  { id: 5, pid: 2 },
  { id: 6, pid: 3 },
  { id: 7, pid: 3 },
  { id: 8, pid: 3 },
  { id: 9, pid: 8 },
  { id: 10, pid: 6 }
];

function arr2tree(arr = []) {
  let rootNode = arr.find(v => v.pid === null);
  if (!rootNode) {
    throw new Error("Expected rootNode not exists");
  }
  let rootNodeIndex = arr.findIndex(v => v.pid === null);
  arr.splice(rootNodeIndex, 1);
  let tree = {
    id: rootNode.id,
    children: []
  };
  let map = {};
  arr.forEach(v => {
    if (!map[v.pid]) {
      map[v.pid] = [];
    }
    map[v.pid].push(v);
  });

  for (const pid in map) {
    let children = map[pid];
    children.forEach(child => {
      if (map[child.id]) {
        child.children = map[child.id];
      }
    });
  }
  tree.children = map[rootNode.id];
  return tree;
}

const tree = arr2tree(arr);

@lhyt
Copy link

lhyt commented Aug 13, 2019

function convertToTree(arr) {
  const MAP = arr.reduce((res, cur) => res.set(cur.id, cur), new Map());
  return [...MAP].reduce((result, [, value]) => {
    const { pId } = value;
    if (pId === undefined) {
      result.push(value)
    } else {
      const parent = map.get(pId);
      parent && (parent.children || (parent.children = [])).push(value);
    }
    return result;
  }, [])
}

@862881015
Copy link

题目都看不懂,pid指父元素的id吗

@flyfox11
Copy link

flyfox11 commented Aug 14, 2019

我来写一个

function recursive(pItem,cArr) {
	let findArr = cArr.filter(item=>item.pId === pItem.id)
	if(findArr.length) {
	   for(let findItem of findArr) {
		delete findItem.pId
		recursive(findItem,cArr)
	   }
	   pItem.children = findArr
	}
 }
 
 function compose(arr) {	
	arr.filter((item,index,array)=>array.findIndex(cell=>cell.id===item.id)===index) //去重
	let pArr = arr.filter(item=>!item.pId)
	let cArr = arr.filter(item=>item.pId)
	for(let pItem of pArr) {
		recursive(pItem,cArr)
	}
	return pArr
 }

@changchangge
Copy link

const fn = arr => {
let res = [];
let map = arr.reduce((res, item) => ((res[item.id] = item), res), {});
for (const item of Object.values(map)) {
if (item.pId) {
map[item.pId].child = map[item.pId].child || [];
map[item.pId].child.push(item);
} else {
res.push(item);
}
}
return res;
};

@romayn-wyb
Copy link

arrayToTree([...new Set(array.map(JSON.stringify))].map(JSON.parse))

function arrayToTree(data, nodesField, idField, parentIdField) {

if (!nodesField) nodesField = 'children';
idField = idField || '_id';
parentIdField = parentIdField || '_pid';

var nodes = [];


var idHash = {};
for (var i = 0, l = data.length; i < l; i++) {
    var o = data[i];
    if (!o) continue;
    var id = o[idField];
    if (id !== null && id !== undefined) {
        idHash[id] = o;
    }
    delete o[nodesField];
}


for (var i = 0, l = data.length; i < l; i++) {
    var o = data[i];
    var p = idHash[o[parentIdField]];
    if (!p) {
        nodes.push(o);
        continue;
    }
    if (!p[nodesField]) {
        p[nodesField] = [];
    }
    p[nodesField].push(o);
}
return nodes;

}

@MissNanLan
Copy link

Object.values(map) 将对象转为数组
学习了

@pagemarks
Copy link

网站类目管理需求?

@lvwxx
Copy link

lvwxx commented Aug 16, 2019

@ZodiacSyndicate

reduce 遍历的时间复杂度不算吗?

@Yxiuchao
Copy link

function transformTree(arr) {
  let res = [];
  let map = arr.reduce((pre, item) => {//去重且进行构建哈希表
    pre[item.id] = item;
    return pre;
  }, {})
  console.log(map)
  for (let item of Object.values(map)) {
    if (!item.pId) {
      res.push(item);
    } else {
      const parent = map[item.pId];
      parent.child = parent.child || [];//当这个元素没有时指向一个数组并将该孩子元素增加进去含有有自己孩子时采用本来的child数组,
      parent.child.push(item)
    }
  }
  return res;
}
console.log(transformTree(arr))

@Yxiuchao
Copy link

var flatLs = [
{ id: 1},
{ id: 2},
{ id: 3},
{ id: 4, pid: 1 },
{ id: 5, pid: 3 },
{ id: 6, pid: 2 },
{ id: 7, pid: 4 },
{ id: 8, pid: 3 },
{ id: 9, pid: 4 }
]
const flat2tree = flatLs => {
flatLs.forEach(item => {
if (!item.pid) {
item.pid = 0;
} else {
const index = flatLs.findIndex(_item => _item.id === item.pid)
if (index !== -1) {
flatLs[index].children = flatLs[index].children || []
flatLs[index].children.push(item)
}
}
})
return flatLs.filter(item => item.pid === 0)
}
为什么代码没有缩进,[笑哭]

用Markdown语法写就有缩进了

@ghost2113
Copy link

Object.values(map) 将对象转为数组
学习了

Object.values()只是获取对象可枚举属性的value值,返回一个数组

@CYYSILVER
Copy link

哈希表,时间复杂度O(n)

const fn = arr => {
  const res = []
  const map = arr.reduce((res, item) => ((res[item.id] = item), res), {})
  for (const item of Object.values(map)) {
    if (!item.pId) {
      res.push(item)
    } else {
      const parent = map[item.pId]
      parent.child = parent.child || []
      parent.child.push(item)
    }
  }
  return res
}

// const arr = [{id: 1}, {id:2, pId: 1}, {id: 3, pId: 2}, {id: 4}, {id:3, pId: 2}, {id: 5, pId: 4}]
// fn(arr) => [{id: 1, child: [{id: 2, pId: 1, child: [{ id: 3, pId: 2}]}]}, {id: 4, child: [{id: 5, pId: 4}]}]
const map = arr.reduce((res, item) => ((res[item.id] = item), res), {})

等同于

const map = {}
arr.forEach((item) => {
    map[item.id] = item
})

我差点还没看懂,太菜了233

@creasy2010
Copy link

/**
 * @desc
 *
 * @使用场景
 *
 * @coder.yang2010@gmail.com
 * @Date    2019/8/28
 **/

let arr: {id: number; pid?: number}[] = [
  {id: 1},
  {id: 2, pid: 1},
  {id: 3, pid: 2},
  {id: 4, pid: 1},
  {id: 5, pid: 3},
  {id: 6, pid: 2},
  {id: 6, pid: 2},
  {id: 2, pid: 1},
];

interface IItem {
  id: number;
  pid?: number;
  child?:IItem[];
}

let ItemsMap: {[id: number]: IItem} = {};
let PidItemsMap: {[pid: number]: IItem[]} = {};
for (let entry of arr) {
  if(ItemsMap[entry.id] ) {
    //去重!!
    continue;
  }
  ItemsMap[entry.id] = entry;

  let _pid = entry.pid || 'master';

  if (!PidItemsMap[_pid]) {
    PidItemsMap[_pid] = [entry];
  } else {
    PidItemsMap[_pid].push(entry);
  }
}

let root = PidItemsMap['master'];

for(let entry  of Object.values(ItemsMap)) {
  entry.child = PidItemsMap[entry.id];
}

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

@qq89987112
Copy link

qq89987112 commented Aug 31, 2019

const arr = [{id: 1}, {id:2, pId: 1}, {id: 3, pId: 2}, {id: 4}, {id:3, pId: 2}, {id: 5, pId: 4}]
function fn (arr) {
    const cache = {}
    const res = []
    for (let index in arr) {
        const item = arr[index]
        const cacheItem = cache[item.id]
        if (!cacheItem || typeof cacheItem.id == 'undefined') {
            const refItem = cacheItem || Object.assign({}, item)
            const refParent = cache[refItem.pId] || {}
            refParent.children = refParent.children || []
            refParent.children.push(refItem)  
            cache[item.pId] = refParent
            if (cacheItem) {
                Object.assign(refItem, item)
            } else {
                cache[item.id] = refItem
            }
            !item.pId && res.push(refItem)
        }
    }
    return res
}
fn(arr)



[
    {
        "id": 1,
        "children": [
            {
                "id": 2,
                "pId": 1,
                "children": [
                    {
                        "id": 3,
                        "pId": 2
                    }
                ]
            }
        ]
    },
    {
        "id": 4,
        "children": [
            {
                "id": 5,
                "pId": 4
            }
        ]
    }
]

@GoodLuckAlien
Copy link

  function formatArr (arr,newArr = []){
     //去重和第一次格式化数组
     let idArr = [],obj={}
     for(let i=0;i<arr.length;i++){
         let val = arr[i]        
        if(!~idArr.indexOf(val.id)){
            idArr.push( val.id ) 
            obj[val.id] = val
           !val.pId &&  newArr.push(val) 
        }
     }
     for(let i in obj ){
         if(obj[i].pId){
            obj[obj[i].pId].children ? obj[ obj[i].pId].children.push(obj[i]) :  obj[obj[i].pId].children = [ obj[i] ]
         }
     }
     return newArr
  }

@Jesseszhang
Copy link

哈希表,时间复杂度O(n)

const fn = arr => {
  const res = []
  const map = arr.reduce((res, item) => ((res[item.id] = item), res), {})
  for (const item of Object.values(map)) {
    if (!item.pId) {
      res.push(item)
    } else {
      const parent = map[item.pId]
      parent.child = parent.child || []
      parent.child.push(item)
    }
  }
  return res
}

// const arr = [{id: 1}, {id:2, pId: 1}, {id: 3, pId: 2}, {id: 4}, {id:3, pId: 2}, {id: 5, pId: 4}]
// fn(arr) => [{id: 1, child: [{id: 2, pId: 1, child: [{ id: 3, pId: 2}]}]}, {id: 4, child: [{id: 5, pId: 4}]}]

@ZodiacSyndicate 👍 厉害!(提个小建议,最好复制一下对象,否则会修改原数组)

const map = arr.reduce((res, item) => ((res[item.id] = Object.assign({}, item)), res), {})

Object.assign是浅拷贝

@Jesseszhang
Copy link

哈希表,时间复杂度O(n)

const fn = arr => {
  const res = []
  const map = arr.reduce((res, item) => ((res[item.id] = item), res), {})
  for (const item of Object.values(map)) {
    if (!item.pId) {
      res.push(item)
    } else {
      const parent = map[item.pId]
      parent.child = parent.child || []
      parent.child.push(item)
    }
  }
  return res
}

// const arr = [{id: 1}, {id:2, pId: 1}, {id: 3, pId: 2}, {id: 4}, {id:3, pId: 2}, {id: 5, pId: 4}]
// fn(arr) => [{id: 1, child: [{id: 2, pId: 1, child: [{ id: 3, pId: 2}]}]}, {id: 4, child: [{id: 5, pId: 4}]}]

@ZodiacSyndicate 👍 厉害!(提个小建议,最好复制一下对象,否则会修改原数组)

const map = arr.reduce((res, item) => ((res[item.id] = Object.assign({}, item)), res), {})

就是应用到了 引用
const fn = arr => {
const res = []
const map = arr.reduce((res, item) => {
// console.log('====res, item====', JSON.stringify(res), JSON.stringify(item));
res[item.id] = item;
// console.log('====res====', JSON.stringify(res));
return res;
}, {})
console.log('=====map====', JSON.stringify(map));
console.log('=====values====', JSON.stringify(Object.values(map)));
for (const item of Object.values(map)) {
if (!item.pId) {
res.push(item);
console.log('====res===', JSON.stringify(res))
} else {
const parent = map[item.pId];
console.log('====parent=====',JSON.stringify(parent))
parent.child = parent.child || [];
parent.child.push(item)
console.log('====parent====',JSON.stringify(parent))
console.log(JSON.stringify(res))
}
}
return res
}
const arr = [{id: 1}, {id:2, pId: 1}, {id: 3, pId: 2}, {id: 4}, {id:3, pId: 2}, {id: 5, pId: 4}]
fn(arr);
VM61519:9 =====map==== {"1":{"id":1},"2":{"id":2,"pId":1},"3":{"id":3,"pId":2},"4":{"id":4},"5":{"id":5,"pId":4}}
VM61519:10 =====values==== [{"id":1},{"id":2,"pId":1},{"id":3,"pId":2},{"id":4},{"id":5,"pId":4}]
VM61519:14 ====res=== [{"id":1}]
VM61519:17 ====parent===== {"id":1}
VM61519:20 ====parent==== {"id":1,"child":[{"id":2,"pId":1}]}
VM61519:21 [{"id":1,"child":[{"id":2,"pId":1}]}]
VM61519:17 ====parent===== {"id":2,"pId":1}
VM61519:20 ====parent==== {"id":2,"pId":1,"child":[{"id":3,"pId":2}]}
VM61519:21 [{"id":1,"child":[{"id":2,"pId":1,"child":[{"id":3,"pId":2}]}]}]
VM61519:14 ====res=== [{"id":1,"child":[{"id":2,"pId":1,"child":[{"id":3,"pId":2}]}]},{"id":4}]
VM61519:17 ====parent===== {"id":4}
VM61519:20 ====parent==== {"id":4,"child":[{"id":5,"pId":4}]}
VM61519:21 [{"id":1,"child":[{"id":2,"pId":1,"child":[{"id":3,"pId":2}]}]},{"id":4,"child":[{"id":5,"pId":4}]}]

@JackFGreen
Copy link

同一个问题? #139

@gauseen
Copy link

gauseen commented Nov 26, 2019

const arr = [
  { id: 1, pid: null },
  { id: 2, pid: 1 },
  { id: 3, pid: 1 },
  { id: 2, pid: 1 },
  { id: 4, pid: 2 },
  { id: 5, pid: 2 },
  { id: 6, pid: 3 },
  { id: 7, pid: 3 },
  { id: 8, pid: 3 },
  { id: 9, pid: 8 },
  { id: 10, pid: 6 }
]

// 去重
const deduplication = (arr) => {
  return arr.filter((item, index) => index === arr.findIndex(child => item.id === child.id))
}

// 递归嵌套
const arrToTree = (arr, pid = null) => {
  return arr.filter(item => item.pid === pid)
   .map(item => ({ ...item, children: arrToTree(arr, item.id)}))
}

const solution = (arr) => {
  return arrToTree(deduplication(arr))
}

solution(arr)

@yangjiedage
Copy link

yangjiedage commented May 1, 2020

利用对象是引用类型,直接通过pId找到父元素

var data = [{id: 1}, {id: 2, pId: 1},{id: 3, pId: 2}]

function bar() {
  let dataNoRepeat = data.reduce((curr, acc) => {
    curr[acc.id] = acc
    return curr
  }, {})
  let tree = {}

  for(let key in dataNoRepeat) {
    const item = dataNoRepeat[key]
    if(item.pId) {
      let parent = dataNoRepeat[item.pId]
      if(parent) {
        if(!parent.children) {
          parent.children = []
        }
        parent.children.push(item)
      }
    } else {
      tree[item.id] = item
    }
  }

  console.log(tree)
}

bar(data)

@823680621
Copy link

823680621 commented Jul 16, 2020

  function handelFn(arr) {
    let obj = {}
    let tree = {}
    async function ff(i) {
      obj[arr[i].pId].child.push(arr[i])
    }
    for (let i = 0; i < arr.length; i++) {
      arr[i].child = []
      obj[arr[i].id] = arr[i]
      if (!arr[i].pId) {
        tree [arr [i].id] = arr [i]
      } else {
        ff(i)
      }
    }
    return tree
  }

@maggie-chen
Copy link

同问,reduce的复杂度 不用算进去么??

@maggie-chen
Copy link

function fn(arr) {
    const res = []
    //创建map结构
    const map = new Map()
    for (let elem of arr.values()) { 
        map[elem.id] = elem
    }
    // 遍历读取
    for (let value of Object.values(map)) {
        if(!value.parentId){
            res.push(value)
        }else{
            const parent = map[value.parentId]
            if(!parent.children) parent.children= []
            parent.children.push(value)
        }
    }
    return res
}

@823680621
Copy link

function handelFunc(srcData) {
let childList = [];
let result = [];
for (let i = 0; i < srcData.length; i++) {
let element = srcData[i];
element.child = childList[element.id] || (childList[element.id] = []);
if (!element.pId) {
result.push(element);
} else {
if (childList[element.pId]) {
childList[element.pId].push(element);
} else {
childList[element.pId] = [element];
}
}
}
return result;
}

@XW666
Copy link

XW666 commented Mar 31, 2021

const find12 = (arr) => {

let map = {}, obj = {}, res = []
//数组去重
arr.forEach(item => {
  if (!obj[JSON.stringify(item)]) {
    obj[JSON.stringify(item)] = item
    map[item.id] = item
  }
})
//转成树形结构
for (const item of Object.values(obj)) {
  if (!item.pid) {
    res.push(item)
  } else {
    if (map[item.pid]) {
      const parent = map[item.pid]
      parent.children = parent.children || []
      parent.children.push(item)
    }
  }
}

return res

}

@xyuh111
Copy link

xyuh111 commented Apr 13, 2022

const map = arr.reduce((res, item) => {
    if (!item.pid) {
        res[item.id] = item
    }
    item.child = arr.filter(it => it.pid && it.pid === item.id)
    return res
}, [])

@823680621
Copy link

823680621 commented Oct 11, 2022 via email

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