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

PHP 實現數組差集操作(A - B)的多種方法

     編輯:PHP 相關知識

PHP 實現數組差集操作(A - B)的多種方法

獲取「存在於數組 A 但不存在於數組 B」的元素是常見需求。本文對比原生函數、手寫循環、鍵值差集等多種實現,分析性能與適用場景。

需求定義

$a = [1, 2, 3, 4, 5, 'a', 'b'];
$b = [3, 4, 'b', 'c'];

// 預期結果:[1, 2, 5, 'a'](保持 A 的順序與鍵名)
// 注意:是否保留鍵名、是否嚴格比較、多維數組如何處理

方法一:array_diff() —— 原生標準函數

<?php
$result = array_diff($a, $b);
// 結果:[0=>1, 1=>2, 4=>5, 5=>'a'](保留原鍵名,重新索引需 array_values())

// 多數組差集
$result = array_diff($a, $b, $c, $d);

// 關鍵特性
// - 比較值(字符串比較,'1' == 1 為 true)
// - 保留 A 的鍵名
// - 一維數組專用
?>

方法二:array_udiff() —— 自定義比較邏輯

<?php
// 嚴格比較(類型+值)
$result = array_udiff($a, $b, fn($x, $y) => $x <=> $y); // PHP 7+
// 或
$result = array_udiff($a, $b, function($x, $y) {
    return ($x === $y) ? 0 : (($x > $y) ? 1 : -1);
});

// 對象/多維數組比較
$objectsA = [['id'=>1], ['id'=>2]];
$objectsB = [['id'=>2]];
$result = array_udiff($objectsA, $objectsB, function($x, $y) {
    return $x['id'] <=> $y['id'];
});
// 結果:[['id'=>1]]
?>

方法三:array_diff_key() / array_diff_ukey() —— 按鍵名差集

<?php
$a = ['x'=>1, 'y'=>2, 'z'=>3];
$b = ['y'=>99, 'w'=>88];

// 按鍵名差集(忽略值)
$result = array_diff_key($a, $b); // ['x'=>1, 'z'=>3]

// 自定義鍵比較
$result = array_diff_ukey($a, $b, 'strcasecmp'); // 大小寫不敏感鍵比較
?>

方法四:手寫循環(性能優化、特殊邏輯)

<?php
/**
 * 高性能差集:利用鍵值查找 O(1) 特性
 * 適用於大數據量、頻繁調用
 */
function arrayDiffFast(array $a, array $b): array {
    // 將 B 轉為鍵值映射(值作為鍵)
    $bMap = array_flip($b); // 值必須能作為鍵(int/string)
    
    $result = [];
    foreach ($a as $key => $value) {
        if (!isset($bMap[$value])) {
            $result[$key] = $value; // 保留原鍵名
        }
    }
    return $result;
}

/**
 * 嚴格模式差集(類型+值)
 */
function arrayDiffStrict(array $a, array $b): array {
    $bMap = [];
    foreach ($b as $v) {
        // 序列化區分類型:1 vs '1'
        $bMap[serialize($v)] = true;
    }
    
    $result = [];
    foreach ($a as $key => $value) {
        if (!isset($bMap[serialize($value)])) {
            $result[$key] = $value;
        }
    }
    return $result;
}
?>

方法五:多維數組差集(遞歸)

<?php
function arrayDiffRecursive(array $a, array $b): array {
    $result = [];
    foreach ($a as $key => $value) {
        if (!array_key_exists($key, $b)) {
            $result[$key] = $value;
        } elseif (is_array($value) && is_array($b[$key])) {
            $diff = arrayDiffRecursive($value, $b[$key]);
            if ($diff) $result[$key] = $diff;
        } elseif ($value !== $b[$key]) {
            $result[$key] = $value;
        }
    }
    return $result;
}

// 示例
$a = ['user' => ['id'=>1, 'tags'=>['a','b']], 'status'=>1];
$b = ['user' => ['id'=>1, 'tags'=>['b']], 'status'=>2];
print_r(arrayDiffRecursive($a, $b));
// ['user' => ['tags'=>['a']], 'status'=>1]
?>

性能基準測試(10萬元素)

<?php
$a = range(1, 100000);
$b = range(50000, 150000);

$start = microtime(true);
$r1 = array_diff($a, $b);
echo "array_diff: " . (microtime(true) - $start) * 1000 . " ms\n"; // ~15ms

$start = microtime(true);
$r2 = arrayDiffFast($a, $b);
echo "arrayDiffFast: " . (microtime(true) - $start) * 1000 . " ms\n"; // ~5ms

$start = microtime(true);
$bMap = array_flip($b);
$r3 = [];
foreach ($a as $k=>$v) if(!isset($bMap[$v])) $r3[$k]=$v;
echo "inline flip: " . (microtime(true) - $start) * 1000 . " ms\n"; // ~4ms
?>

對比總結表

方法比較方式保留鍵名多維支援性能推薦場景
array_diff鬆散 (==)是否中通用一維數組
array_udiff自定義是是(遞歸)慢對象、複雜比較
array_diff_key鍵名是否快鍵基差集
array_flip+isset鬆散可選否最快大數據、高頻
serialize+isset嚴格 (===)可選否快需區分類型
遞歸自寫自定義是是中多維結構差異

常見陷阱避坑

  1. array_diff 不重新索引:結果鍵名不連續,需 `array_values()` 重置。
  2. 類型轉換陷阱:`array_diff([1], ['1']) === []`,嚴格場景用 `serialize` 或 `array_udiff`。
  3. 多維數組直接比較失效:`array_diff([['a']], [['a']])` 會報錯「Array to string conversion」,必須用 `array_udiff` 或遞歸。
  4. NULL 值處理:`array_flip` 會丟棄 NULL,嚴格場景需特殊處理。

根據數據規模、嚴格程度、維度選擇合適方法,`array_flip + isset` 是高性能通用首選。

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