在抽獎、驗證碼、隨機抽樣等情境下,常需要從指定範圍取出不重複的隨機數字。本文介紹兩種常見做法:陣列打亂法與迴圈檢查法,並實測其記憶體與執行時間表現。
建立 1 到 N 的陣列,用 shuffle() 打亂後取前 k 個。
function createRandID_shuffle($max, $count = 11) {
$arr = range(1, $max);
shuffle($arr);
return implode(',', array_slice($arr, 0, $count));
}
優點:程式碼簡潔、保證不重複。
缺點:需建立完整陣列,記憶體消耗隨 $max 線性增長。當 $max = 900,000 時,已觸發 Allowed memory size exhausted 錯誤。
用 while 迴圈產生隨機數,以 in_array() 檢查是否重複,直到集齊所需數量。
function createRandID_loop($max, $count = 11) {
$arr = [];
while (count($arr) < $count) {
$num = rand(1, $max);
if (!in_array($num, $arr)) {
$arr[] = $num;
}
}
return implode(',', $arr);
}
優點:記憶體固定(僅存結果陣列),不受 $max 影響。
缺點:當 $count 接近 $max 時,碰撞機率極高,效能急劇下降;但 $count 較小時極快。
| 範圍 | 方法 | 耗時(秒) | 記憶體 |
|---|---|---|---|
| 700,000 | shuffle | 0.67 | 約 28 MB |
| 700,000 | loop | 0.00016 | < 1 MB |
| 999,999 | shuffle | OOM | 超出 128 MB |
| 999,999 | loop | 0.00014 | < 1 MB |
array_rand()function createRandID_modern($max, $count = 11) {
$keys = array_rand(array_flip(range(1, $max)), $count);
sort($keys);
return implode(',', $keys);
}
註:array_flip(range(...)) 仍會建立大陣列,記憶體問題未解。若 $max 極大,建議改用 Reservoir Sampling 或資料庫 ORDER BY RAND() LIMIT k。
shuffle 或 array_rand 最簡潔。