分層資料Hierarchical Data探索(例如:無限級分類、多級選單、省份城市)
引言
什麼是分層資料?
類似於樹形結構,除了根節點和葉子節點外,所有節點都有一個父節點和一個或多個子節點。
大多數同學都曾在資料庫中處理過分層資料(hierarchical data),分層資料存在於許多基於資料庫的應用程式中,包括論壇和郵件列表中的分類、商業組織圖表、內容管理系統的分類、產品分類、無限級分類、多級選單、省份城市等等。但是因為關聯式資料庫中的表沒有層次關係,只是簡單的平面化的列表;而分層資料具有父-子關係,顯然關聯式資料庫中的表不能自然地表現出其分層的特性。
接下來我會先通過一般方法和遞迴(recursion)方法來實現無限極分類,然後再通過兩種資料模型來談一談分層資料的處理。
- 分層資料Hierarchical Data探索(1.遞迴 recursion)
- 分層資料Hierarchical Data探索(2.鄰接表模型 Adjacency List Model)
- 分層資料Hierarchical Data探索(3.巢狀集合模型 Nested Set Model)
三種方式的變數傳遞
- & 引用賦值
function doloop1(&$i = 1)
{
print_r($i);
$i++;
if ($i <= 10) {
doloop1($i);
}
}
doloop1();
- static 靜態變數
function doloop2()
{
static $i = 1;
print_r($i);
$i++;
if ($i <= 10) {
doloop2();
}
}
doloop2();
- global 全域性變數
$i = 1;
function doloop3()
{
global $i;
echo $i;
$i++;
if ($i <= 10) {
doloop3();
}
}
doloop3();
構建模擬資料
# 模擬資料
$data = [
['id' => 1, 'title' => 'Electronics', 'parent_id' => 0],
['id' => 2, 'title' => 'Laptops & PC', 'parent_id' => 1],
['id' => 3, 'title' => 'Laptops', 'parent_id' => 2],
['id' => 4, 'title' => 'PC', 'parent_id' => 2],
['id' => 5, 'title' => 'Cameras & photo', 'parent_id' => 1],
['id' => 6, 'title' => 'Camera', 'parent_id' => 5],
['id' => 7, 'title' => 'Phones & Accessories', 'parent_id' => 1],
['id' => 8, 'title' => 'Smartphones', 'parent_id' => 7],
['id' => 9, 'title' => 'Android', 'parent_id' => 8],
['id' => 10, 'title' => 'iOS', 'parent_id' => 8],
['id' => 11, 'title' => 'Other Smartphones', 'parent_id' => 8],
['id' => 12, 'title' => 'Batteries', 'parent_id' => 7],
['id' => 13, 'title' => 'Headsets', 'parent_id' => 7],
['id' => 14, 'title' => 'Screen Protectors', 'parent_id' => 7],
];
獲取無限極分類
/**
* 值引用獲取無限極分類樹
*
* @param array $data
* @return array
*/
function make_tree($data)
{
$refer = array();
$tree = array();
foreach($data as $k => $v){
$refer[$v['id']] = & $data[$k]; //建立主鍵的陣列引用
}
foreach($data as $k => $v){
$parent_id = $v['parent_id']; //獲取當前分類的父級id
if($parent_id == 0){
$tree[] = & $data[$k]; //頂級欄目
}else{
if(isset($refer[$parent_id])){
$refer[$parent_id]['children'][] = & $data[$k]; //如果存在父級欄目,則新增進父級欄目的子欄目陣列中
}
}
}
return $tree;
}
/**
* 遞迴獲取無限極分類樹
*
* @param array $data
* @param int $parent_id
* @param int $level
* @return array
*/
function make_tree2($data = [], $parent_id = 0, $level = 0)
{
$tree = [];
if ($data && is_array($data)) {
foreach ($data as $v) {
if ($v['parent_id'] == $parent_id) {
$tree[] = [
'id' => $v['id'],
'level' => $level,
'title' => $v['title'],
'parent_id' => $v['parent_id'],
'children' => make_tree2($data, $v['id'], $level + 1),
];
}
}
}
return $tree;
}
獲取子節點以及節點的層級
/**
* 引用賦值方式
* @param array $data
* @param int $id
* @param int $level
* @return array
*/
function getSubTree($data = [], $id = 0, $level = 0)
{
static $tree = [];
foreach ($data as $key => $value) {
if ($value['parent_id'] == $id) {
$value['laravel'] = $level;
$tree[] = $value;
getSubTree($data, $value['id'], $level + 1);
}
}
return $tree;
}
/**
* 靜態變數方式
* @param array $data
* @param int $id
* @param int $level
* @return array
*/
function getSubTree($data = [], $id = 0, $level = 0)
{
static $tree = [];
foreach ($data as $key => $value) {
if ($value['parent_id'] == $id) {
$value['laravel'] = $level;
$tree[] = $value;
getSubTree($data, $value['id'], $level + 1);
}
}
return $tree;
}
/**
* 全域性變數方式
* @param array $data
* @param int $id
* @param int $level
* @return array
*/
$tree = []; //先申明變數
function getSubTree($data = [], $id = 0, $level = 0)
{
global $tree;
foreach ($data as $key => $value) {
if ($value['parent_id'] == $id) {
$value['laravel'] = $level;
$tree[] = $value;
getSubTree($data, $value['id'], $level + 1);
}
}
return $tree;
}
通過pid獲取所有上級分類 常用於麵包屑導航
/**
* getParentsByParentId2($categories, 9)
*
* @param array $data
* @param $parent_id
* @return array
*/
function getParentsByParentId($data = [], $parent_id)
{
static $categories = [];
if ($data && is_array($data)) {
foreach ($data as $item) {
if ($item['id'] == $parent_id) {
$categories[] = $item;
getParentsByParentId($data, $item['parent_id']);
}
}
}
return $categories;
}
function getParentsByParentId2($data = [], $parent_id)
{
$categories = [];
if ($data && is_array($data)) {
foreach ($data as $item) {
if ($item['id'] == $parent_id) {
$categories[] = $item;
$categories = array_merge($categories, getParentsByParentId2($data, $item['parent_id']));
}
}
}
return $categories;
}
全部更新完成。
- 分層資料Hierarchical Data探索(1.遞迴 recursion)
- 分層資料Hierarchical Data探索(2.鄰接表模型 Adjacency List Model)
- 分層資料Hierarchical Data探索(3.巢狀集合模型 Nested Set Model)
- 著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。
- 文章來源https://blog.arunfung.com