[英]Create nested object from array javascript
我有一個 SharePoint 列表,我通過 REST 在 javascript 中進行操作。 我需要將數組從 REST 轉換為嵌套對象。 我正在基於結構構建導航菜單。 該數組由 ID、Title、Parent 和 Level 組成。 級別是 Top、Mid 或 Bot,Parent 列出作為其父項的條目的 Title。
let orgs = [{
id: "0",
title: "A",
parent: "",
level: "Top"
},{
id: "1",
title: "Org A1",
parent: "A",
level: "Middle"
},
{
id: "2",
title: "Org A2",
parent: "A",
level: "Middle"
},
{
id: "3",
title: "Org A3",
parent: "A",
level: "Middle"
},
{
id: "5",
title: "Org A1-A",
parent: "Org A1",
level: "Bottom"
},
{
id: "6",
title: "Org A1-B",
parent: "Org A1",
level: "Bottom"
},
{
id: "7",
title: "Org A2-A",
parent: "Org A2",
level: "Bottom"
},
{
id: "8",
title: "Org A2-B",
parent: "Org A2",
level: "Bottom"
},
{
id: "9",
title: "Org A3-A",
parent: "Org A3",
level: "Bottom"
},
{
id: "10",
title: "Org A3-B",
parent: "Org A3",
level: "Bottom"
}
];
我正在嘗試遍歷數組並將子項的標題添加到適當的父項。 對象的目標結構是:
const orgObj = {
Title: "Org A",
mid: [{
Title: "Org A1",
bot: [{
Title: "Org A1-A"
}, {
Title: "Org A1-B"
}]
}, {
Title: "Org A2",
bot: [{
Title: "Org A2-A"
}, {
Title: "Org A2-B"
}]
}, {
Title: "Org A3",
bot: [{
Title: "Org A3-A"
}, {
Title: "Org A3-B"
}]
}]
};
我試圖使用地圖功能,但我無法讓結果正常工作。 我一直在這幾天斷斷續續,似乎無法讓它工作。 到目前為止,我無法訪問我在當前位置嘗試過的代碼,但我會在可以獲得它時嘗試更新。 在我看來,這不應該是復雜的。
這是一種方法...
let orgs = [{ id: "0", title: "Org A", parent: "", level: "Top" },{ id: "1", title: "Org A1", parent: "Org A", level: "Middle" }, { id: "2", title: "Org A2", parent: "Org A", level: "Middle" }, { id: "3", title: "Org A3", parent: "Org A", level: "Middle" }, { id: "5", title: "Org A1-A", parent: "Org A1", level: "Bottom" }, { id: "6", title: "Org A1-B", parent: "Org A1", level: "Bottom" }, { id: "7", title: "Org A2-A", parent: "Org A2", level: "Bottom" }, { id: "8", title: "Org A2-B", parent: "Org A2", level: "Bottom" }, { id: "9", title: "Org A3-A", parent: "Org A3", level: "Bottom" }, { id: "10", title: "Org A3-B", parent: "Org A3", level: "Bottom" } ]; let roots = {}; orgs.forEach(org => { if (org.parent) { let parent = orgs.find(o => o.title === org.parent) if (parent.level === 'Top') { if (!parent.mid) parent.mid = []; parent.mid.push(org); } else if (parent.level === 'Middle') { if (!parent.bot) parent.bot = []; parent.bot.push(org); } } else { roots[org.title] = org; } }) console.log(JSON.stringify(Object.values(roots), null, 2));
您可以使用以下算法在線性時間O(n)
為您構建樹。
我在這里大量使用Maps
來保持運行時線性。
首先,我創建了一個將每個title
映射到相應數據的Map
。 我稍后需要這個,以便我可以快速查找組織可能擁有的任何父級的數據。 結果將是這樣的:
Map(10) {
'A' => { id: '0', title: 'A', parent: '', level: 'Top' },
'Org A1' => { id: '1', title: 'Org A1', parent: 'A', level: 'Middle' },
'Org A2' => { id: '2', title: 'Org A2', parent: 'A', level: 'Middle' },
'Org A3' => { id: '3', title: 'Org A3', parent: 'A', level: 'Middle' },
'Org A1-A' => { id: '5', title: 'Org A1-A', parent: 'Org A1', level: 'Bottom' },
'Org A1-B' => { id: '6', title: 'Org A1-B', parent: 'Org A1', level: 'Bottom' },
'Org A2-A' => { id: '7', title: 'Org A2-A', parent: 'Org A2', level: 'Bottom' },
'Org A2-B' => { id: '8', title: 'Org A2-B', parent: 'Org A2', level: 'Bottom' },
'Org A3-A' => { id: '9', title: 'Org A3-A', parent: 'Org A3', level: 'Bottom' },
'Org A3-B' => { id: '10', title: 'Org A3-B', parent: 'Org A3', level: 'Bottom' }
}
然后我還在級別和道具名稱之間創建一個映射,以說明您沒有統一的children
道具,而是mid
或bot
,具體取決於父級。
現在開始實際的樹構建。 我再次使用reduce()
遍歷所有組織,並從一個空的 JavaScript 對象開始。 對於每個項目,我創建目標對象( newObj
),它只包含Title
並使用上面的Map
獲取父對象。 如果沒有父元素,這是最頂層的元素。
如果它不是父對象,我可以使用我的quickRefs
Map
在orgChart
對象中查找對父對象的引用。 然后我引用了樹中的父節點。 現在我需要根據父級的級別獲取children
級屬性mid
或bot
的名稱。
現在使用該屬性名稱,我可以為父節點分配這個新屬性,其值為新的子對象。 如果父對象已經有一個子對象,我可以簡單地將另一個子對象推送到該數組上,如果沒有,我需要創建一個新數組並將子對象推送到該數組上。
最后但並非最不重要的一點是,我需要將對新對象的引用插入到我的quickRefs
Map
中,所以如果我以后遇到一個對象是現在插入的項目的子對象,我可以如上所述直接將子對象分配給該對象。
const input = [ { id: "0", title: "A", parent: "", level: "Top", }, { id: "1", title: "Org A1", parent: "A", level: "Middle", }, { id: "2", title: "Org A2", parent: "A", level: "Middle", }, { id: "3", title: "Org A3", parent: "A", level: "Middle", }, { id: "5", title: "Org A1-A", parent: "Org A1", level: "Bottom", }, { id: "6", title: "Org A1-B", parent: "Org A1", level: "Bottom", }, { id: "7", title: "Org A2-A", parent: "Org A2", level: "Bottom", }, { id: "8", title: "Org A2-B", parent: "Org A2", level: "Bottom", }, { id: "9", title: "Org A3-A", parent: "Org A3", level: "Bottom", }, { id: "10", title: "Org A3-B", parent: "Org A3", level: "Bottom", }, ]; // store titles to their data so we can find a parent object in constant time const map = input.reduce((all, cur) => (all.set(cur.title, cur), all), new Map()); // mapping for the property names // if the parent is level "Top", we need to use "mid" // if the parent is level "Middle", we need to use "bot" const mapLevelToPropName = { Top: "mid", Middle: "bot", } // stores references to objects within the object, so they can be accessed in constant time const quickRefs = new Map(); const output = input.reduce((orgChart, org) => { const parent = map.get(org.parent); const newObj = { Title: org.title } if(parent === undefined) { // top most org orgChart = newObj } else { // some org in the middle which has a parent // get the reference to the parent within the JS object using the quickRefs map const refToParentObj = quickRefs.get(org.parent) // determine the name of the "children" property based on the level of the parent const propName = mapLevelToPropName[parent.level]; // check if there already are childrens (mid, bot) // if yes: append another one to array if(refToParentObj[propName]) refToParentObj[propName].push(newObj); // if no: add new object within an array else refToParentObj[propName] = [newObj]; } // add a reference to the new object into the quickRefs map so // when we find a child we can just grab that reference and add the child quickRefs.set(org.title, newObj); return orgChart; }, {}) console.log(JSON.stringify(output, null, 2));
.as-console-wrapper { max-height: 100% !important; top: 0; }
此實現假定子組織僅出現在輸入數組中的父組織之后,但適用於深度嵌套的結構(盡管“mid”、“bot”功能可能不適合此)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.