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

PHP 多維數組按指定鍵值分組合並:遞歸實現 combine_same_val 算法詳解

     編輯:PHP 相關知識

問題描述

給定一個多維數組,需將 $key 字段值相同的元素合併為一組,結果以 $newkey 字段值為鍵的二維數組返回。例如:

$data = [
    ['id'=>1, 'type'=>'A', 'val'=>10],
    ['id'=>2, 'type'=>'A', 'val'=>20],
    ['id'=>3, 'type'=>'B', 'val'=>30],
];
// 按 type 分組,新鍵為 id
// 結果:
[
    'A' => [ ['id'=>1,'type'=>'A','val'=>10], ['id'=>2,'type'=>'A','val'=>20] ],
    'B' => [ ['id'=>3,'type'=>'B','val'=>30] ]
]

遞歸算法實現

<?php
/**
 * 按指定字段分組合並數組
 * @param array  $array   待處理數組 (引用傳遞,會被修改)
 * @param mixed  $start   當前分組的基準值 (首次調用傳 $array[0][$key])
 * @param string $key     分組依據的字段名
 * @param string $newkey  結果數組的鍵名字段
 * @return array 分組後的關聯數組
 */
function combine_same_val(array &$array, $start, $key, $newkey) {
    static $result = []; // 靜態變量累積結果

    foreach ($array as $k => $v) {
        if ($v[$key] == $start) {
            $result[$v[$newkey]][] = $v;
            unset($array[$k]); // 從源數組移除已處理項
        }
    }

    // 重新索引並檢查是否還有剩餘
    $array = array_values($array);
    if (!empty($array)) {
        // 遞歸處理下一組,基準值為新數組首個元素的 $key
        combine_same_val($array, $array[0][$key], $key, $newkey);
    }

    return $result;
}

// --- 測試 ---
$data = [
    ['id'=>1, 'type'=>'A', 'val'=>10],
    ['id'=>2, 'type'=>'A', 'val'=>20],
    ['id'=>3, 'type'=>'B', 'val'=>30],
    ['id'=>4, 'type'=>'B', 'val'=>40],
    ['id'=>5, 'type'=>'C', 'val'=>50],
];

$grouped = combine_same_val($data, $data[0]['type'], 'type', 'id');
print_r($grouped);
/* 輸出:
Array
(
    [1] => Array ( [0] => Array ([id]=>1 [type]=>A [val]=>10) [1] => Array ([id]=>2 [type]=>A [val]=>20) )
    [3] => Array ( [0] => Array ([id]=>3 [type]=>B [val]=>30) [1] => Array ([id]=>4 [type]=>B [val]=>40) )
    [5] => Array ( [0] => Array ([id]=>5 [type]=>C [val]=>50) )
)
*/
?>

算法分析

  • 時間複雜度:O(n²) — 每次遞歸遍歷剩餘數組,並在其中查找匹配項。大數據量下效率較低。
  • 空間複雜度:O(n) — 結果數組 + 遞歸棧。
  • 副作用:原數組 $array 被修改 (元素被 unset),調用後原數組為空。
  • 靜態變量:static $result 導致函數不可重入,同一進程中第二次調用會疊加上次結果,需手動 unset($result) 或改用非靜態方式。

優化版:單次遍歷 O(n) 實現 (推薦生產使用)

<?php
function groupByKey(array $array, string $groupKey, string $resultKey): array {
    $result = [];
    foreach ($array as $item) {
        $gVal = $item[$groupKey] ?? null;
        $rVal = $item[$resultKey] ?? null;
        if ($gVal === null || $rVal === null) continue; // 跳過缺鍵項
        $result[$gVal][$rVal] = $item; // 若 $resultKey 不唯一會覆蓋,可改用 [] 自動索引
    }
    return $result;
}

// 使用
$grouped = groupByKey($data, 'type', 'id');
/* 結果結構:
[
    'A' => [ 1 => [...], 2 => [...] ],
    'B' => [ 3 => [...], 4 => [...] ],
    'C' => [ 5 => [...] ]
]
*/
?>

進階:Laravel Collection / Symfony 組件

// Laravel
collect($data)->groupBy('type')->map(function($g) {
    return $g->keyBy('id')->all();
})->all();

// 純 PHP 單行 (PHP 5.5+)
array_reduce($data, function($c, $v) {
    $c[$v['type']][$v['id']] = $v; return $c;
}, []);

總結

原遞歸寫法適合理解遞歸思想與靜態變量特性,但**生產環境請使用單次遍歷 O(n) 寫法**,代碼更簡潔、性能高數量級、無副作用、可重入。若使用現代框架,優先調用內置 Collection 方法。

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