將JSON一維數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)化為樹形數(shù)據(jù)結(jié)構(gòu)的JS方法

將JSON一維數(shù)據(jù)結(jié)構(gòu)轉(zhuǎn)化為樹形數(shù)據(jù)結(jié)構(gòu)是編程中的基本算法,這里總結(jié)一下,當然,也參考了一些前人的經(jīng)驗。

復習一下傳址賦值(又叫引用賦值)

研究轉(zhuǎn)化方法之前,先了解一下傳址賦值,它是解決JSON結(jié)構(gòu)轉(zhuǎn)化的一個前提,如果沒有傳址賦值這種特性,咱們的方法就復雜多了。

看代碼:

var a = {
  b: {
    c: 1
  }
}

var x = a.b

a.b.c = 2

console.log(x) // {c: 2}

可以看出,表面上var x = a.b在前,a.b.c = 2重賦值在后,但是在前賦值的變量確實會被在后賦值的代碼所影響。道理很簡單,當一個變量的值為數(shù)組或?qū)ο蟮臅r候,變量的值并不會在內(nèi)存中克隆一份,而是直接指向數(shù)組或者對象的內(nèi)存原地址,只要原數(shù)據(jù)有變化,變量也就等于有變化了。下面是數(shù)組的例子,你以為x是永遠不變的[2,3]么?并不是:

var a = [1,[2,3],4]

var x = a[1]

a[1][1] = 6

console.log(x) // [2, 6]

JSON一維結(jié)構(gòu)轉(zhuǎn)樹形結(jié)構(gòu)的要求

首先先明確一維結(jié)構(gòu)的寫法,比如,讓你將某國軍隊的從屬關(guān)系存入數(shù)據(jù)表,你怎么存?

比較普遍的寫法是:

var jsonData = [{
    "id": "1",
    "pid": "0",
    "name": "第一戰(zhàn)區(qū)"
}, {
    "id": "4",
    "pid": "1",
    "name": "第1軍"
}, {
    "id": "5",
    "pid": "4",
    "name": "第1師"
}]

也就是說,使用pid標記上級,這樣一級級的追溯,最終可以形成樹狀結(jié)構(gòu),大致如下:

var jsonData = [{
    "id": "1",
    "pid": "0",
    "name": "第一戰(zhàn)區(qū)",
    "children": [
        {
            "id": "4",
            "pid": "1",
            "name": "第1軍",
            "children": [
                {
                    "id": "5",
                    "pid": "4",
                    "name": "第1師"
                }
            ]
        }
    ]
}]

思路

  1. 利用臨時數(shù)組變量,將無序的JSON數(shù)據(jù)編制序列。
    因為默認的JSON結(jié)構(gòu),你無法迅速定位一個想要的元素,如果用臨時數(shù)組變量,將元素按照id存入數(shù)組,就可以快速定位元素。
  2. 遍歷JSON的每一個元素,去臨時變量里尋找它的父元素,如果找到,就填到這個父元素的children里面,如果找不到父元素,說明它就是一級元素。
    最終將所有一級元素push到result變量即可。
    這里就涉及到一個問題,就是如果先發(fā)生了一級元素已經(jīng)push到result變量,那么之后再發(fā)生下級元素填到該一級元素的children里,還來得及么?
    這里就用到JS的傳址賦值的特點了,所以答案是:來得及。

代碼

代碼的JSON使用了別人的一個例子,而函數(shù)是我自己寫的:

var jsonData = [{
    "id": "1",
    "pid": "0",
    "name": "家用電器"
}, {
    "id": "4",
    "pid": "1",
    "name": "大家電"
}, {
    "id": "5",
    "pid": "1",
    "name": "生活電器"
}, {
    "id": "2",
    "pid": "0",
    "name": "服飾"
}, {
    "id": "3",
    "pid": "0",
    "name": "化妝"
}, {
    "id": "7",
    "pid": "4",
    "name": "空調(diào)"
}, {
    "id": "8",
    "pid": "4",
    "name": "冰箱"
}, {
    "id": "9",
    "pid": "4",
    "name": "洗衣機"
}, {
    "id": "10",
    "pid": "4",
    "name": "熱水器"
}, {
    "id": "11",
    "pid": "3",
    "name": "面部護理"
}, {
    "id": "12",
    "pid": "3",
    "name": "口腔護理"
}, {
    "id": "13",
    "pid": "2",
    "name": "男裝"
}, {
    "id": "14",
    "pid": "2",
    "name": "女裝"
}, {
    "id": "15",
    "pid": "7",
    "name": "海爾空調(diào)"
}, {
    "id": "16",
    "pid": "7",
    "name": "美的空調(diào)"
}, {
    "id": "19",
    "pid": "5",
    "name": "加濕器"
}, {
    "id": "20",
    "pid": "5",
    "name": "電熨斗"
}];

function flat2tree(jsonData){
    var result = [], temp = {}, i = 0, j = 0, len = jsonData.length
    for(; i < len; i++){
        temp[jsonData[i]['id']] = jsonData[i] // 以id作為索引存儲元素,可以無需遍歷直接定位元素
    }
    for(; j < len; j++){
        var currentElement = jsonData[j]
        var tempCurrentElementParent = temp[currentElement['pid']] // 臨時變量里面的當前元素的父元素
        if (tempCurrentElementParent) { // 如果存在父元素
          if (!tempCurrentElementParent['children']) { // 如果父元素沒有chindren鍵
            tempCurrentElementParent['children'] = [] // 設(shè)上父元素的children鍵
          }
          tempCurrentElementParent['children'].push(currentElement) // 給父元素加上當前元素作為子元素
        } else { // 不存在父元素,意味著當前元素是一級元素
            result.push(currentElement);
        }
    }
    return result;
}

console.log(flat2tree(jsonData))

更新一種代碼量極簡,但運算復雜度較高的算法

速度比上一種算法慢9倍,但是勝在代碼足夠簡單。

// jsonData 從略
function flat2tree(pid, arr) {
  return arr.filter(item => item.pid === pid).map(item => ({...item, children: flat2tree(item.id, arr)}))
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 1.ios高性能編程 (1).內(nèi)層 最小的內(nèi)層平均值和峰值(2).耗電量 高效的算法和數(shù)據(jù)結(jié)構(gòu)(3).初始化時...
    歐辰_OSR閱讀 30,194評論 8 265
  • Swift1> Swift和OC的區(qū)別1.1> Swift沒有地址/指針的概念1.2> 泛型1.3> 類型嚴謹 對...
    cosWriter閱讀 11,621評論 1 32
  • 第2章 基本語法 2.1 概述 基本句法和變量 語句 JavaScript程序的執(zhí)行單位為行(line),也就是一...
    悟名先生閱讀 4,506評論 0 13
  • 有這樣的一群人,他們做了一個這樣的約定:當成員人數(shù)達到77人時,就抱團成一個班,在每月逢7倍數(shù)的當天里,提交一篇文...
    悠南說影閱讀 1,334評論 7 7
  • 深夜獨坐在書桌前, 有些敏感,又有些脆弱, 不知是否是生理期即將到來的緣故。 可笑的是, 想找種方式, 來盡力宣泄...
    SeeYou_jiaoer閱讀 271評論 0 0

友情鏈接更多精彩內(nèi)容