給定一個多維數組,需將 $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) )
)
*/
?>
$array 被修改 (元素被 unset),調用後原數組為空。static $result 導致函數不可重入,同一進程中第二次調用會疊加上次結果,需手動 unset($result) 或改用非靜態方式。<?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
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 方法。