多叉樹結構的數據,parent表示法轉成children表示法

来源:https://www.cnblogs.com/LQ996/archive/2018/11/11/9942545.html
-Advertisement-
Play Games

最近碰到的問題,有個數組,數組元素是對象,該對象的結構就如樹的parent表示法的節點一樣。形象點講就是該數組存放了樹的所有“葉子節點”,並且葉子節點記憶體有父節點,一直到根節點為止,就如存了一條從葉子節點到根節點路徑。 現在有要求是將這個數組轉成一個children表示法的對象,即從根節點開始,每個 ...


最近碰到的問題,有個數組,數組元素是對象,該對象的結構就如樹的parent表示法的節點一樣。形象點講就是該數組存放了樹的所有“葉子節點”,並且葉子節點記憶體有父節點,一直到根節點為止,就如存了一條從葉子節點到根節點路徑。

現在有要求是將這個數組轉成一個children表示法的對象,即從根節點開始,每個節點存有其子節點數組。轉化效果如下(節點必須有個唯一標識符,以下id就是,並且轉化前後其他屬性保持不變,這裡為了顯示簡潔沒有加入其他屬性。):

核心思想是使用遞歸,新建唯一的根節點開始,不斷生長出子節點。並再插入子節點時判斷子節點是否存在,存在的話不插入,反之插入。註意所有將子節點插入到父節點children數組的操作,都必須保證被插入父節點已經是“新建的唯一根節點”下的,這樣才能實現不斷生長的效果。以下通過遞歸返回父節點的方式確保,返回前是一次插入操作,這時已經判斷出“插入新節點”和“未插入新節點”,根據這兩種情況,遞歸返回值就可以判斷,如果插入新節點則返回該新節點作為父節點,反之返回已存在於“唯一根節點上的”的“該節點”作為父節點。

 1 var treeConverter = {
 2         result: null, //轉化後的結果,是根節點,所有節點都是從根節點長出來的
 3         attributeName: 'id', //節點唯一標識符
 4         needFind: true, //是否查詢節點在result中已經存在,為了優化效率
 5         transform: function (node) { //轉化遞歸函數,參數:一個待插入節點
 6             if (node.parent != null) { //該節點有父節點
 7                 var newNode = this.transform(node.parent); //遞歸進入,返回值為一個節點,用作父節點,該父節點必然存在於result中,這點由下麵的演算法可以控制
 8                 if (this.needFind) {
 9                     for (var i = 0; i < newNode.children.length; i++) { //查找要插入的node子節點是否在newNode這個父節點中存在
10                         if (newNode.children[i][this.attributeName] === node[this.attributeName]) {
11                             return newNode.children[i]; //存在的話直接返回newNode父節點內的該子節點,該子節點必然存在於result中,作為返回值它將被用作上級遞歸的newNode,因此newNode必然存在於result中
12                         }
13                     }
14                 }
15                 this.needFind = false; //不存在的話,關閉之後遞歸的迴圈判斷,因為待插入node節點不存在於result中,故而它的子節點一定不存在於result中,不用再迴圈判斷
16                 delete node.parent; //刪除該節點的parent屬性,如果有的話
17                 node.children = []; //因為確定是要新插入的節點,沒有children:[]屬性,故給該節點增加children:[]屬性
18                 newNode.children.push(node); //將該node節點push進newNode的子節點數組中
19                 return node; //return該新插入節點,作為遞歸返回值給上層,用作newNode父節點,node存在於result中故newNode存在於result中
20             } else if (node.parent == null) { //該葉節點沒有父節點,即為根節點
21                 delete node.parent; //刪除該節點的parent屬性,如果有的話
22                 if (this.result == null) { //根節點不存在
23                     node.children = []; //給該節點增加children:[]屬性
24                     return this.result = node; //該節點賦給result,並return根節點,作為返回值它將被用作上級遞歸的newNode,因此newNode必然存在於result中
25                 } else {
26                     return this.result // 直接return根節點,作為返回值它將被用作上級遞歸的newNode,因此newNode必然存在於result中
27                 }
28             }
29         },
30         getSingle: function (node, attributeName) { //傳入單個葉子節點,attributeName作為節點唯一標識符屬性,返回單個轉化結果
31             this.result = null; //重置根節點
32             this.needFind = true; //重置開啟節點是否已存在判斷
33             this.attributeName = attributeName == null ? 'id' : attributeName; //唯一標識符預設為“id”
34             this.transform(JSON.parse(JSON.stringify(node))); //複製出一個新的節點對象作為參數,保證不改變原有數據
35             return this.result; //返回根節點
36         },
37         getWhole: function (nodes, attributeName) { //傳入整個葉子節點數組,attributeName作為節點唯一標識符屬性,返回整個轉化結果
38             this.result = null; //重置根節點
39             this.attributeName = attributeName == null ? 'id' : attributeName; //唯一標識符預設為“id”
40             nodes = JSON.parse(JSON.stringify(nodes)); //複製出一個新的節點對象作為參數,保證不改變原有數據
41             nodes.forEach(item => { //迴圈調用轉化方法
42                 this.needFind = true; //重置開啟節點是否已存在判斷,保證不插入重覆節點
43                 this.transform(item);
44             })
45             return this.result; //返回根節點
46         }
47     }
48     var result = treeConverter.getWhole(nodes); //調用

 

模擬數據:

var nodes= [
    {
        id: 2,
        parent: {
            id: 5,
            parent: {
                id: 3,
                parent: null
            }
        }
    },
    {
        id: 1,
        parent: {
            id: 5,
            parent: {
                id: 3,
                parent: null
            }
        }
    },
    {
        id: 4,
        parent: {
            id: 7,
            parent: {
                id: 3,
                parent: null
            }
        }
    },
    {
        id: 14,
        parent: {
            id: 13,
            parent: {
                id: 9,
                parent: {
                    id: 8,
                    parent: {
                        id: 7,
                        parent: {
                            id: 3,
                            parent: null
                        }
                    }
                }
            }
        }
    },
    {
        id: 6,
        parent: {
            id: 7,
            parent: {
                id: 3,
                parent: null
            }
        }
    },
    {
        id: 10,
        parent: {
            id: 8,
            parent: {
                id: 7,
                parent: {
                    id: 3,
                    parent: null
                }
            }
        }
    }
]

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • source map 用來調試打包後的代碼 ...
  • 管理html的bundle依賴 html webpack plugin可以自動給html添加bundle文件 清理dist文件夾 ...
  • 載入Css webpack並不能處理js以外的靜態資源,通過loader來支持他們 載入圖片 file loader可以處理圖片資源,字體資源 載入數據 ...
  • 文章目錄 html代碼用JS動態載入進頁面 JS判斷用戶訪問的是PC還是mobile或者微信瀏覽器 判斷瀏覽器的簡單有效方法 點擊某個div區域之外,隱藏該div 如何在手機上禁止瀏覽器的網頁滾動 改變type=file預設樣式,"瀏覽"等字體 js使用console.time列印代碼執行時間 js ...
  • 1、js動態設置html的字體大小 設計稿寬度750px,設備寬度350px,此時HTML 的font-size:50px,及1rem=50px; 假設一元素在設計稿上寬度為750px,750/100=7.5rem(7.5*50=375px)。 計算方法:設計稿的尺寸 / 100 = XXX rem ...
  • 一 原型: 1 定義:原型是function對像的一個屬性,他定義了構造函數製造出的對象的公共祖先; 通過該構造函數產生的對象,可以繼承該原型的屬性和方法。 原型也是對像。prototype; Person.prototype.name = 'jams'; function Person(){ } ...
  • 屬性 HTML標簽可以設置屬性,屬性一般以鍵值對的方式寫在開始標簽中 1.HTML標簽除一些特定屬性外可以設置自定義屬性,一個標簽可以設置多個屬性用空格分隔,多個屬性不區分先後順序。 2.屬性值要用引號包裹起來,通常使用雙引號也可以單引號。 3.屬性和屬性值不區分大小寫,但是推薦使用小寫... ...
  • 主要的信息都是來自於下方所示的網站 https://webpack.docschina.org/configuration 從 webpack 4.0.0 版本開始,可以不用通過引入一個配置文件打包項目。然而,webpack 仍然還是高度可配置的 ,並且能夠很好的滿足需求。 首先總結下個人理解的,w ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...