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

PHP shuffle 陣列隨機打亂與取樣實戰:關聯陣列保鍵、array_rand 對比與大數據優化

     編輯:PHP 相關知識

PHP shuffle 陣列隨機打亂與取樣實戰:關聯陣列保鍵、array_rand 對比與大數據優化

shuffle() 原地打亂陣列順序並**重置數字鍵 (0...n-1)**,關聯鍵名會**遺失**。本文說明此行為、保留鍵名的替代方案、array_rand() 隨機取鍵用法、以及百萬級陣列抽樣的記憶體優化策略。

一、shuffle 基本行為與陷阱

<?php
$data = [
    ['name' => 'A', 'rank' => 40],
    ['name' => 'B', 'rank' => 50],
    ['name' => 'C', 'rank' => 60],
    ['name' => 'D', 'rank' => 50],
];
shuffle($data);
// $data 現在順序隨機,但鍵已重置為 0,1,2,3
// 取前 2 筆
$sample = array_slice($data, 0, 2);
?>

關鍵點:

  • 回傳 bool (成功/失敗),**陣列原地修改**。
  • **關聯陣列鍵名會消失**:['a'=>1, 'b'=>2] → [0=>1, 1=>2]。
  • 使用 Mersenne Twister (同 mt_rand),速度快、分布均勻。

二、保留關聯鍵名的 shuffle_assoc

<?php
function shuffle_assoc(array &$array): void {
    $keys = array_keys($array);
    shuffle($keys);
    $result = [];
    foreach ($keys as $key) {
        $result[$key] = $array[$key];
    }
    $array = $result;
}

// 測試
$assoc = ['id1' => 'A', 'id2' => 'B', 'id3' => 'C'];
shuffle_assoc($assoc);
// 鍵名 id1/id2/id3 保留,順序隨機
?>

或用 uksort($arr, fn() => mt_rand(-1, 1)) (但分布不如 shuffle 均勻)。

三、array_rand:隨機取鍵 (不打亂原陣列)

<?php
$arr = ['a' => 10, 'b' => 20, 'c' => 30, 'd' => 40];
$keys = array_rand($arr, 2); // 取 2 個鍵,回傳陣列
// $keys 如 ['c', 'a']
$sample = array_intersect_key($arr, array_flip($keys));
// $sample = ['c' => 30, 'a' => 10]
?>
  • 第二參數 $num:取鍵數量;省略時回傳單一鍵 (字串)。
  • **不修改原陣列**,適合只需抽樣不需打亂場景。
  • 同樣基於 MT,PHP 7.1+ 自動播種。

四、大數據量 (百萬級) 抽樣優化

問題:shuffle($millionItems) 需載入整個陣列記憶體,且 O(n) 打亂耗時。

方案 A:資料庫層面抽樣 (最推薦)

-- MySQL: 高效隨機取樣 (避免 ORDER BY RAND())
SELECT * FROM `table` 
WHERE id >= (SELECT FLOOR(RAND() * (SELECT MAX(id) FROM `table`)))
ORDER BY id LIMIT 10;

方案 B:水塘抽樣 (單次遍歷、常數記憶體)

<?php
function reservoirSample(iterable $source, int $k): array {
    $reservoir = [];
    $i = 0;
    foreach ($source as $item) {
        if ($i < $k) {
            $reservoir[] = $item;
        } else {
            $j = mt_rand(0, $i);
            if ($j < $k) $reservoir[$j] = $item;
        }
        $i++;
    }
    return $reservoir;
}
// 使用:直接遍歷 Generator/資料庫游標,記憶體 O(k)
$sample = reservoirSample($db->createCommand('SELECT * FROM big_table')->query(), 100);
?>

方案 C:系統隨機 ID 範圍 (需 ID 連續/近似均勻)

$ids = range(1, $maxId);
shuffle($ids);
$sampleIds = array_slice($ids, 0, 100);
// 再 WHERE id IN (...) 查詢

五、對比總結表

函數修改原陣列保留關聯鍵用途記憶體
shuffle是否 (重置)打亂順序、取前 NO(n)
shuffle_assoc是是打亂順序、保鍵O(n)
array_rand否是 (回傳鍵)隨機取鍵/子集O(n)
reservoirSample否視來源海量/串流抽樣O(k)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved