PHP 快速掃描列表建立無限極分類樹

Wi1dcard發表於2019-06-20

書接上回。上文結尾,講解了引用的妙用。剛好,在我現在所處公司的業務裡有一處用遞迴實現的「省市區」分級列表;本文將這一用途搬進生產環境,通過優化此省市區列表,試試真正的效果如何。

廢話不多說,上程式碼。

省市區列表結構

array(
    1 => array(
            'id' => 1,
            'name' => '中華人民共和國',
            'parent_id' => 0,
            'level' => 'country',
        ),
    2 => array(
            'id' => 2,
            'name' => '北京市',
            'parent_id' => 1,
            'level' => 'province',
        ),
    20 => array(
            'id' => 20,
            'name' => '天津市',
            'parent_id' => 1,
            'level' => 'province',
        ),
    38 => array(
            'id' => 38,
            'name' => '河北省',
            'parent_id' => 1,
            'level' => 'province',
        ),
    218 => array(
            'id' => 218,
            'name' => '山西省',
            'parent_id' => 1,
            'level' => 'province',
        ),
    349 => array(
            'id' => 349,
            'name' => '內蒙古自治區',
            'parent_id' => 1,
            'level' => 'province',
        ),
    465 => array(
            'id' => 465,
            'name' => '遼寧省',
            'parent_id' => 1,
            'level' => 'province',
        ),
    ...
);

優化前

/**
* 獲取以父級 ID 為 $parent_id 為根節點的樹型結構陣列
*
* @param array $arr
* @param int $level 樹型當前層
* @param int $parent_id 父級id
* @param int $floor 樹型總層數
* @return array
*/
public static function getList(&$arr, $level = 0, $parent_id = 1, $floor = 3)
{
    if ($level != 0) {
        $empty = $arr[$parent_id];
        $empty['list'] = [];
        $emptyPointer = &$empty['list'];
    } else {
        $empty = [];
        $emptyPointer = &$empty;
    }
    if ($level < $floor) {
        $ok = false;
        foreach ($arr as $index => &$item) {
            if ($item['parent_id'] == $parent_id) {
                $data = self::getList($arr, $level + 1, $index);
                array_push($emptyPointer, $data);
                $ok = true;
            }
            if ($ok && $item['parent_id'] != $parent_id) {
                break;
            }
        }
    }

    return $empty;
}

優化後

function getStructuredTree($list)
{
    $tree = [];

    foreach ($list as &$item) {
        $parent_id = $item['parent_id'];

        if (isset($list[$parent_id]) && !empty($list[$parent_id])) {
            $list[$parent_id]['list'][] = &$item;
        } else {
            $tree[] = &$item;
        }
    }
    // unset($item);

    return $tree[0]['list']; // 根節點只有中華人民共和國,所以直接返回中國的所有子節點
}

效果

以下為此函式執行 1000 次取平均值。

函式執行時間 (ms) memory_get_peak_usage() 峰值記憶體 (MB)
優化前 157.65 2516192 2.39
優化後 2.01 987872 0.94

僅供參考,不同環境生成的具體數值可能差異較大,只關注優化前後的對比就好。

我感謝自己平凡,敢愛敢恨沒負擔。
我感謝自己不凡,可愛可恨都包攬。

相關文章