PHP 內建 shuffle() 僅支援一維數組,且**重置數字鍵名**。多維數組直接使用會導致子數組順序不變,或結構破壞。
function shuffle_assoc($list) {
if (!is_array($list)) return $list;
$keys = array_keys($list);
shuffle($keys);
$random = [];
foreach ($keys as $key) {
$random[$key] = $list[$key];
}
return $random;
}
原理:提取鍵名 → 打亂鍵名 → 按新順序重建數組。保持關聯鍵名不變。
function shuffle_assoc_recursive($list) {
if (!is_array($list)) return $list;
$keys = array_keys($list);
shuffle($keys);
$random = [];
foreach ($keys as $key) {
$random[$key] = shuffle_assoc_recursive($list[$key]);
}
return $random;
}
特點:遞歸處理每一層,**所有層級鍵名順序均被打亂**,值結構保持不變。
function rec_assoc_shuffle($array) {
$ary_keys = array_keys($array);
$ary_values = array_values($array);
shuffle($ary_values);
foreach ($ary_keys as $key => $value) {
if (is_array($ary_values[$key]) && $ary_values[$key] !== NULL) {
$ary_values[$key] = rec_assoc_shuffle($ary_values[$key]);
}
$new[$value] = $ary_values[$key];
}
return $new;
}
差異:版本 B 先 array_values() 取值再打亂,再按原鍵名順序映射回新值;版本 A 直接打亂鍵名。版本 B 更符合「值隨機重新分配給鍵名」的語義。
$data = [
'a' => [1, 2, 3],
'b' => [4, 5, 6],
'c' => ['x' => 7, 'y' => 8],
];
echo "原數組:\n"; print_r($data);
echo "\n版本A:\n"; print_r(shuffle_assoc_recursive($data));
echo "\n版本B:\n"; print_r(rec_assoc_shuffle($data));
| 方案 | 鍵名保持 | 值順序隨機化 | 遞歸深度 | 適用場景 |
|---|---|---|---|---|
| shuffle() | ❌ 重置為 0..n | ✅ | 僅一維 | 簡單索引數組 |
| shuffle_assoc | ✅ | ✅ (頂層) | 一維 | 關聯數組打亂 |
| 版本 A | ✅ (所有層) | ✅ (所有層) | 無限 | 樹形結構、配置數組 |
| 版本 B | ✅ (所有層) | ✅ (所有層) | 無限 | 數據洗牌、測試數據生成 |
&$array 減少內存複製srand() 保證可復現function shuffle_recursive(array &$array): void {
$keys = array_keys($array);
shuffle($keys);
$shuffled = [];
foreach ($keys as $key) {
$val = $array[$key];
if (is_array($val)) {
shuffle_recursive($val);
}
$shuffled[$key] = $val;
}
$array = $shuffled;
}
PHP 原生 shuffle() 功能受限,多維數組打亂需自行實現遞歸方案。版本 B (rec_assoc_shuffle) 語義最清晰:值隨機重新分配給固定鍵名,並遞歸處理子數組。實際項目中根據業務語義選擇「打亂鍵名順序」或「打亂值分配」,並注意深度限制與性能優化。