需從 1~25 中隨機抽取 16 個不重複數字,且要填補 200 筆缺失投票記錄。普通 array_unique 去重效率低,本文介紹「翻翻法」優化方案。
<?php
/**
* 生成指定範圍、指定數量的不重複隨機數
* @param int $min 最小值
* @param int $max 最大值
* @param int $num 需要數量
* @return array 隨機數陣列(鍵名連續 0~n-1)
*/
function unique_rand($min, $max, $num) {
$return = array();
while (count($return) < $num) {
$return[] = mt_rand($min, $max);
// 翻翻法去重:利用鍵值互換特性,比 array_unique 快數倍
$return = array_flip(array_flip($return));
}
// 打亂並重置鍵名,保證 0~n-1 連續
shuffle($return);
return array_values($return);
}
// 使用示例
$arr = unique_rand(1, 25, 16);
sort($arr); // 如需有序輸出
echo implode(',', $arr); // 例:2,3,4,6,7,8,9,10,11,12,13,16,20,21,22,24
?>
mt_rand() 替代 rand()Mersenne Twister 算法,速度快 4 倍,隨機質量更高,適合大量生成場景。
$arr = [2, 5, 2, 8];
$flipped = array_flip($arr); // [2 => 0, 5 => 1, 8 => 3] 鍵值互換,重複值被覆蓋
$unique = array_flip($flipped); // [2, 5, 8] 再次互換回原值
利用陣列鍵名唯一性,兩次 array_flip 即可完成去重,效能遠優於 array_unique。
shuffle() + array_values() 重置鍵名去重後鍵名可能不連續(如 [0 => 2, 2 => 5, 4 => 8]),shuffle 打亂順序並重新索引,配合 array_values 保證輸出為標準連續索引陣列,便於後續 foreach 遍歷。
若範圍極大(如 1~1000000 取 500000),上述方法會因碰撞導致循環次數暴增。改用 範圍洗牌法:
function unique_rand_large($min, $max, $num) {
$range = range($min, $max); // 建立完整範圍
shuffle($range); // 全量打亂
return array_slice($range, 0, $num); // 截取前 N 個
}
時間複雜度 O(N),記憶體佔用 O(N),適合範圍不超過百萬級場景。
| 場景 | 推薦方法 | 複雜度 |
|---|---|---|
| 小範圍、小數量(<10000) | mt_rand + 翻翻法 | O(k) 期望 |
| 大範圍、大數量(>10000) | range + shuffle + slice | O(N) |
| 極大範圍、極少數量 | 隨機集合 + 布隆過濾器 | O(k) 空間換時間 |
根據業務數據規模選擇最優策略,避免過度優化或性能瓶頸。