首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 多維陣列搜尋指定值:遞歸與迭代兩種實作模式完整解析

     編輯:PHP 相關知識

問題場景

需在二維或多維陣列中判斷某值是否存在,PHP 內建 in_array() 僅支援一維陣列,需自行實作遞歸或迭代遍歷。

方案一:二維陣列專用(迭代 + in_array)

function search_2d($keyword, array $stack): bool
{
    foreach ($stack as $subArray) {
        if (in_array($keyword, $subArray, true)) { // strict 模式建議開啟
            return true;
        }
    }
    return false;
}

// 使用範例
$data = [
    ['id' => 1, 'name' => 'Alice'],
    ['id' => 2, 'name' => 'Bob'],
];
var_dump(search_2d('Alice', $data)); // true
var_dump(search_2d('Charlie', $data)); // false

適用場景:固定二維結構、效能優先、不需知道具體鍵名路徑。

方案二:任意深度多維陣列(遞歸回傳匹配路徑)


/**
 * 遞歸搜尋多維陣列,回傳所有包含目標值的鍵路徑
 *
 * @param array  $array  目標陣列
 * @param mixed  $value  搜尋值
 * @param array  $path   內部遞歸用:當前路徑
 * @return array 扁平化的路徑陣列,每項為 ['path' => [...], 'value' => mixed]
 */
function search_recursive(array $array, $value, array $path = []): array
{
    $results = [];
    foreach ($array as $key => $val) {
        $currentPath = array_merge($path, [$key]);
        if (is_array($val)) {
            // 遞歸進入子陣列
            $results = array_merge($results, search_recursive($val, $value, $currentPath));
        } elseif ($val === $value) { // 嚴格比較
            $results[] = ['path' => $currentPath, 'value' => $val];
        }
    }
    return $results;
}

// 使用範例
$data = [
    'users' => [
        ['id' => 1, 'tags' => ['admin', 'vip']],
        ['id' => 2, 'tags' => ['editor']],
    ],
    'settings' => ['theme' => 'dark', 'lang' => 'zh-TW'],
];

$matches = search_recursive($data, 'vip');
print_r($matches);
/*
Array
(
    [0] => Array
        (
            [path] => Array ( [0] => users [1] => 0 [2] => tags [3] => 1 )
            [value] => vip
        )
)
*/

方案三:迭代器模式(記憶體友善,適合超大陣列)


class RecursiveArraySearch implements Iterator
{
    private $iterator;
    private $target;
    private $currentMatch;

    public function __construct(array $array, $target)
    {
        $this->iterator = new RecursiveIteratorIterator(
            new RecursiveArrayIterator($array),
            RecursiveIteratorIterator::LEAVES_ONLY
        );
        $this->target = $target;
    }

    public function rewind() { $this->iterator->rewind(); $this->findNext(); }
    public function valid()  { return $this->currentMatch !== null; }
    public function current() { return $this->currentMatch; }
    public function key()    { return $this->iterator->getSubIterator()->key(); }
    public function next()   { $this->iterator->next(); $this->findNext(); }

    private function findNext()
    {
        $this->currentMatch = null;
        foreach ($this->iterator as $key => $val) {
            if ($val === $this->target) {
                // 建構完整路徑
                $path = [];
                for ($depth = $this->iterator->getDepth(); $depth >= 0; $depth--) {
                    $path[] = $this->iterator->getSubIterator($depth)->key();
                }
                $this->currentMatch = ['path' => array_reverse($path), 'value' => $val];
                break;
            }
        }
    }
}

// 使用:foreach 逐個取得匹配,不一次載入所有結果
foreach (new RecursiveArraySearch($hugeArray, 'target') as $match) {
    echo "Found at: " . implode(' → ', $match['path']) . "\n";
    // 可隨時 break 停止搜尋
}

效能與選型建議

方案時間複雜度空間複雜度優點缺點
二維迭代O(n×m)O(1)簡單、快速、無遞歸風險僅限二維
遞歸回傳陣列O(N)O(D + R)取得完整路徑、程式碼直觀深度過大可能堆疊溢位、一次產生所有結果佔記憶體
RecursiveIteratorIteratorO(N)O(D)惰性求值、記憶體恆定、支援中斷程式碼較複雜、路徑建構需手動

N = 總元素數,D = 最大深度,R = 匹配結果數。

常見陷阱提醒

  • 嚴格比較:預設 in_array() 及 == 會將 "1" 與 1 視為相同,建議一律使用 === 或 in_array($v, $arr, true)。
  • 循環引用:陣列若包含自身引用($a[] = &$a),遞歸會無限迴圈。需維護 $visited = [] 記錄 spl_object_id() 或序列化指紋。
  • 大陣列效能:若頻繁搜尋同一大陣列,考慮建立倒排索引(值 → 鍵路徑映射)或改用資料庫全文搜尋。

整理自 heicm 技術筆記,補充遞歸路徑回傳與迭代器模式實作

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved