在處理多維陣列時,常會遇到「根據某個鍵名,快速找出其父層鍵名與父層資料」的需求。本文將分享一個由簡單函式演進為完整類別的實作過程,並解決同名鍵衝突的問題。
核心概念是遞迴遍歷陣列,建立「鍵名 → 父鍵名」的一維索引表:
<?php
function indexKey($data, $parent = NULL) {
$arr = array();
foreach ($data as $key => $value) {
$arr[$key] = $parent;
if (is_array($value)) {
$arr += indexKey($value, $key);
}
}
return (Array)$arr;
}
?>
輸出範例:
Array
(
[china] =>
[name] => china
[cite] => china
[beijing] => cite
[site] => beijing
[chaoyang] => site
[xuanwu] => site
[shanghai] => cite
[jingan] => site
[huangpu] => site
)
缺點:若陣列中存在同名鍵(如多個 name),後者會覆蓋前者,導致資料遺失。
改用類別封裝,索引值改為陣列以儲存多個父鍵:
<?php
class IndexKey {
private $_arr = array();
public function __construct($data) {
$this->_createIndex($data);
}
public function printArr() {
return (Array)$this->_arr;
}
public function search($key) {
return isset($this->_arr[$key]) ? $this->_arr[$key] : NULL;
}
private function _createIndex($data, $parent = NULL) {
foreach ($data as $key => $value) {
$this->_checkIndex($key, $parent);
if (is_array($value)) {
$this->_createIndex($value, $key);
}
}
}
private function _checkIndex($key, $parent) {
$index = isset($this->_arr[$key]) ? $this->_arr[$key] : NULL;
if ($index) {
if (is_array($index)) {
array_push($this->_arr[$key], $parent);
} else {
$this->_arr[$key] = array($index, $parent);
}
} else {
$this->_arr[$key] = $parent;
}
}
}
?>
使用方式:
$index = new IndexKey($arr);
print_r($index->printArr());
echo $index->search('beijing'); // 輸出 cite
echo $index->search('name'); // 輸出 Array ( [0] => china [1] => beijing [2] => shanghai )
進一步強化,索引同時記錄「父鍵名」與「父層完整資料」:
<?php
class IndexArr {
private $_arr = array();
public function __construct($data) {
$this->_createIndex($data);
}
public function printArr() {
return (Array)$this->_arr;
}
public function search($key) {
return isset($this->_arr[$key]) ? $this->_arr[$key]['parent'] : NULL;
}
public function parentValue($key) {
return isset($this->_arr[$key]) ? $this->_arr[$key]['data'] : NULL;
}
private function _createIndex($data, $parent = NULL) {
foreach ($data as $key => $value) {
$this->_checkIndex($key, $parent, $data);
if (is_array($value)) {
$this->_createIndex($value, $key);
}
}
}
private function _checkIndex($key, $parent, $data) {
$data = $parent && isset($data[$parent]) ? $data[$parent] : $data;
!isset($this->_arr[$key]) && $this->_arr[$key] = array('data' => $data, 'parent' => '');
$index = &$this->_arr[$key]['parent'];
if (!empty($index)) {
if (is_array($index)) {
array_push($index, $parent);
} else {
$index = array($index, $parent);
}
} else {
$index = $parent;
}
}
}
?>
現在可以一次取得父鍵名與父層資料:
$index2 = new IndexArr($arr);
echo $index2->search('beijing'); // cite
print_r($index2->parentValue('beijing')); // 取得 cite 節點完整陣列
完整原始碼可下載:php_arr.rar