PHP實(shí)現(xiàn)無(wú)限級(jí)分類(lèi)(遞歸+引用)

原始數(shù)據(jù)

  • 數(shù)據(jù)庫(kù)


    原始數(shù)據(jù)
  • 打印到頁(yè)面


    原始數(shù)據(jù)

遞歸

  • 遞歸的思路就是【找兒子】,也就是循環(huán)所有數(shù)據(jù),找到每條數(shù)據(jù)的所有兒子、兒子的兒子、兒子的兒子的兒子....,首先我們知道要找test1的兒子就是找所有pid為1的數(shù)據(jù),于是遍歷整個(gè)數(shù)組找到了test1-1和test1-2;然后還要分別找test1-1和test1-2的兒子,就這樣一直找下去,由于每次找兒子的方法都是一樣的,就是遍歷所有數(shù)據(jù)(除開(kāi)自己的長(zhǎng)輩,因?yàn)殚L(zhǎng)輩不可能是兒孫),找出符合條件的,唯一不同的就是每次找兒子的爹不一樣,代碼如下:
function getChild($data, $id = 0)
    {
        //初始化兒子
        $child = [];
        //循環(huán)所有數(shù)據(jù)找$id的兒子
        foreach ($data as $key => $datum) {
            //找到兒子了
            if ($datum['pid'] == $id) {
                //保存下來(lái),然后繼續(xù)找兒子的兒子
                $child[$datum['id']] = $datum;
                //先去掉自己,自己不可能是自己的兒孫
                unset($data[$key]);
                //遞歸找,并把找到的兒子放到一個(gè)child的字段中
                $child[$datum['id']]['child'] = $this->getChild($data, $datum['id']);
            }
        }
        return $child;
    }

運(yùn)行結(jié)果:


遞歸運(yùn)行結(jié)果

引用

  • 引用確實(shí)是一個(gè)非常巧妙的方法,也不用像遞歸那樣循環(huán)那么多次,思路就是首先把所有數(shù)據(jù)以id為索引重新排列,排列之后長(zhǎng)這個(gè)樣子:


    重排之后的數(shù)據(jù)
  • 然后重點(diǎn)來(lái)啦?。。∪缓笾恍枰业礁?jié)點(diǎn),也就是pid是0的三條數(shù)據(jù),把它們放到一個(gè)全新的數(shù)組中,注意:這里的放并不是簡(jiǎn)單的賦值,而是引用之前的地址。這兩者有什么不同呢,這里簡(jiǎn)單幾個(gè)例子說(shuō)明一下:
    function test(){
        $a=1;
        $b=$a;  //賦值
        $b1=&$a;//賦址
        $a=2;
        dump('$b的值是:'.$b);
        dump('$b1的值是:'.$b1);
    }

最開(kāi)始$a初始化為1,把$a的值(也就是1)賦給變量$b,然后把$a的地址(內(nèi)存地址)賦給$b1,然后改變$a的值,再查看$b$b的值。結(jié)果如下:

傳值和傳址的區(qū)別

我們發(fā)現(xiàn)$b的值還是1,而$b1的值卻跟隨著$a的改變而改變了,這就是因?yàn)?code>$b保存的是$a的地址,無(wú)論$a怎么變他們的值都會(huì)保持一致。
回到我們之前的問(wèn)題上來(lái),我們用新的數(shù)組保存了根節(jié)點(diǎn)的地址,后面無(wú)論根節(jié)點(diǎn)怎么變我們的新數(shù)組都會(huì)和變化過(guò)后的數(shù)據(jù)保持一致;那么不是根節(jié)點(diǎn)的數(shù)據(jù)怎么處理呢,我們這里可以把它的地址放到他爹的兒子節(jié)點(diǎn)當(dāng)中,這樣的話就是一層層引用,最后所有的數(shù)據(jù)都被新數(shù)組引用了。
說(shuō)了這么多,代碼如下:

function getChild($data)
    {
        $tree = [];
        $newData = [];
        //循環(huán)重新排列
        foreach ($data as $datum) {
            $newData[$datum['id']] = $datum;
        }
        foreach ($newData as $key => $datum) {
            if ($datum['pid'] > 0) {
                //不是根節(jié)點(diǎn)的將自己的地址放到父級(jí)的child節(jié)點(diǎn)
                $newData[$datum['pid']]['child'][] = &$newData[$key];
            } else {
                //根節(jié)點(diǎn)直接把地址放到新數(shù)組中
                $tree[] = &$newData[$datum['id']];
            }
        }
        return $tree;
    }

運(yùn)行結(jié)果:


引用運(yùn)行結(jié)果

參考文檔

https://www.cnblogs.com/vishun/p/6716483.html

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 包(lib)、模塊(module) 在Python中,存在包和模塊兩個(gè)常見(jiàn)概念。 模塊:編寫(xiě)Python代碼的py...
    清清子衿木子水心閱讀 3,897評(píng)論 0 27
  • 一、Python簡(jiǎn)介和環(huán)境搭建以及pip的安裝 4課時(shí)實(shí)驗(yàn)課主要內(nèi)容 【Python簡(jiǎn)介】: Python 是一個(gè)...
    _小老虎_閱讀 6,313評(píng)論 0 10

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