머리말
우리 모두는 프로젝트에서 이러한 요구에 직면했을 것입니다: 트리를 평면화하거나 평면화된 데이터를 트리 구조로 변환하는 것은 일반적으로 시스템 인증과 같은 프로젝트에서 발생합니다. 다음 단계는 데이터 처리를 백엔드에서 요구하는 형식으로 변환하는 것입니다.
데이터 평면화
- 평면화된 배열
let arr = [
{
id: 1, name: '1', pid: 0 },
{
id: 2, name: '2', pid: 1 },
{
id: 3, name: '3', pid: 1 },
{
id: 4, name: '4', pid: 3 },
{
id: 5, name: '5', pid: 3 },
]
- 나무
let tree = [
{
id: 1,
name: '1',
pid: 0,
children: [
{
id: 2,
name: '2',
pid: 1,
children: [],
},
{
id: 3,
name: '3',
pid: 1,
children: [
{
id: 4,
name: '4',
pid: 3,
children: [],
},
],
},
],
},
]
나무 평탄화
재귀적 구현
- 트리를 순회하여 각 항목을 결과 집합에 추가합니다. 자식이 있고 길이가 0이 아닌 경우 재귀적으로 순회합니다.
- 여기서는 구조 분해 할당을 사용하여 각 노드의 하위 속성을 제거해야 합니다.
function treeToArray(tree) {
let res = []
for (const item of tree) {
const {
children, ...i } = item
if (children && children.length) {
res = res.concat(treeToArray(children))
}
res.push(i)
}
return res
}
구현을 줄이다
function treeToArray(tree) {
return tree.reduce((res, item) => {
const {
children, ...i } = item
return res.concat(
i,
children && children.length ? treeToArray(children) : []
)
}, [])
}
배열을 트리로 평면화
재귀적 구현
- 가장 일반적으로 사용되는 방법은 재귀적 구현이며 아이디어는 비교적 간단합니다. 트리의 부모 노드와 부모 ID를 전달하고 배열 쿼리를 반복하여 해당 자식 노드를 찾아서 부모 노드로 푸시하는 방법을 구현합니다. 그런 다음 재귀적으로 하위 노드를 찾습니다.
function arrayToTree(items) {
let res = []
let getChildren = (res, pid) => {
for (const i of items) {
if (i.pid === pid) {
const newItem = {
...i, children: [] }
res.push(newItem)
getChildren(newItem.children, newItem.id)
}
}
}
getChildren(res, 0)
return res
}
지도 객체 구현
- 1. 먼저 지도를 전송한 후 해당 관계를 찾으세요.
- 아이디어: 먼저 데이터를 맵으로 변환하여 저장한 다음 객체의 참조를 사용하여 횡단하는 동안 맵에서 해당 데이터를 직접 찾아 저장합니다.
- Object.prototype.hasOwnProperty: 이 메소드는 객체 자체 속성에 지정된 속성이 있는지 여부를 나타내는 부울 값을 반환하고 프로토타입 체인에서 상속된 속성을 무시합니다.
function arrayToTree(items) {
let res = [] // 存放结果集
let map = {
}
// 先转成map存储
for (const i of items) {
map[i.id] = {
...i, children: [] }
}
for (const i of items) {
const newItem = map[i.id]
if (i.pid === 0) {
res.push(newItem)
} else {
if (Object.prototype.hasOwnProperty.call(map, i.pid)) {
map[i.pid].children.push(newItem)
}
}
}
return res
}
- 2. 지도 저장을 하면서 해당 관계를 찾아보세요.
- 아이디어: 항목의 id를 키로 반복하여 맵에 저장합니다. 이미 키-값 쌍이 있으면 저장할 필요가 없습니다. 동시에 항목의 pid가 아닌지 확인하세요. 맵의 키에 직접적으로 부모-자식 관계에 해당합니다. 맵에서 키-값 쌍을 생성하는 것이 아닌 경우 키는 pid이고 부모-자식 관계에 해당합니다.
function arrayToTree(items) {
let res = [] // 存放结果集
let map = {
}
// 判断对象是否有某个属性
let getHasOwnProperty = (obj, property) =>
Object.prototype.hasOwnProperty.call(obj, property)
// 边做map存储,边找对应关系
for (const i of items) {
map[i.id] = {
...i,
children: getHasOwnProperty(map, i.id) ? map[i.id].children : [],
}
const newItem = map[i.id]
if (i.pid === 0) {
res.push(newItem)
} else {
if (!getHasOwnProperty(map, i.pid)) {
map[i.pid] = {
children: [],
}
}
map[i.pid].children.push(newItem)
}
}
return res
}