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

PHP array_unique 與 array_flip+array_keys 效能深度解析

     編輯:PHP 綜合知識

去除陣列重複值時,array_unique() 是最直觀的選擇,但實測發現 array_keys(array_flip($arr)) 或雙重 array_flip() 效能遠優於前者。本文從 C 原始碼層面剖析兩者實作差異,揭示效能落差根本原因。

實測效能對比

$test = [];
for ($i = 0; $i < 10000; $i++) {
    $test[] = rand(0, 100); // 大量重複值
}

// array_unique
$start = microtime(true);
$out = array_unique($test);
echo 'array_unique: ' . (microtime(true) - $start) . "s\n"; // ~0.069s

// array_flip + array_keys
$start = microtime(true);
$out = array_keys(array_flip($test));
echo 'flip + keys: ' . (microtime(true) - $start) . "s\n"; // ~0.0015s

// 雙重 array_flip
$start = microtime(true);
$out = array_flip(array_flip($test));
echo 'flip + flip: ' . (microtime(true) - $start) . "s\n"; // ~0.0014s

結論:array_flip 方案比 array_unique 快約 45 倍。

原始碼層面剖析

array_keys 實作(ext/standard/array.c)

  • 遍歷輸入陣列,將鍵值直接插入新陣列
  • 核心呼叫 zend_hash_next_index_insert()
  • 哈希表插入平均 O(1),整體 O(n)
  • 若鍵值重複,新值直接覆蓋舊值

array_flip 實作

  • 遍歷輸入陣列,將「值」作為新鍵、「鍵」作為新值插入
  • 同樣使用哈希表插入 zend_hash_index_update() / zend_symtable_update()
  • 重複值會被後者覆蓋,天然具備去重效果
  • 整體 O(n)

array_unique 實作

  • 複製陣列至新哈希表
  • 建立 Bucket 指標陣列 arTmp
  • 呼叫 zend_qsort() 進行 快速排序(塊樹排序變體)
  • 遍歷排序後陣列,比較相鄰元素刪除重複
  • 核心開銷在排序:**O(n log n)**

為何排序會慢這麼多?

  1. 記憶體分配:需額外分配 Bucket 索引陣列
  2. 比較函數開銷:php_array_data_compare 需處理型別轉換、字串比較等
  3. 快排遞迴調用:函數呼叫堆疊與分區邏輯額外負擔
  4. 刪除操作:排序後仍需逐個 zend_hash_del 移除重複項

實務建議

場景推薦寫法備註
純量值陣列去重(int/string)array_keys(array_flip($arr))最快,保留最後出現的鍵名
需保留第一次出現的鍵名array_flip(array_flip($arr))雙重 flip 會反轉兩次,保留首次鍵名
物件陣列或需自訂比較邏輯array_unique($arr, SORT_REGULAR)唯一支援物件比較的內建函數
關聯陣列需保留鍵名關係同上flip 會丟失原鍵名

補充:PHP 7.3+ 優化

PHP 7.3 起 array_unique() 針對整數陣列優化了排序演算法,但哈希表方案在大多數情況下仍具優勢。建議:

  • 單純標量去重 → array_keys(array_flip())
  • 複雜型別或需保留語意 → array_unique()

理解底層實作差異,能在效能敏感路徑做出正確選擇,避免不必要的 CPU 浪費。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved