PHP Conference Japan 2024

array_diff

(PHP 4 >= 4.0.1, PHP 5, PHP 7, PHP 8)

array_diff計算陣列的差異

描述

array_diff(array $array, array ...$arrays): array

比較 array 與一個或多個其他陣列,並傳回 array 中不存在於任何其他陣列中的值。

參數

array

要從中比較的陣列

arrays

要比較的陣列

傳回值

傳回一個 array,其中包含 array 中所有不存在於任何其他陣列中的項目。 array 陣列中的鍵會被保留。

變更記錄

版本 描述
8.0.0 此函數現在可以使用只有一個參數來呼叫。以前,至少需要兩個參數。

範例

範例 #1 array_diff() 範例

<?php
$array1
= array("a" => "green", "red", "blue", "red");
$array2 = array("b" => "green", "yellow", "red");
$result = array_diff($array1, $array2);

print_r($result);
?>

$array1 中的多次出現都會被視為相同。這將輸出

Array
(
    [1] => blue
)

範例 #2 array_diff() 範例,使用不相符的型別

只有在 (string) $elem1 === (string) $elem2 時,兩個元素才會被視為相等。也就是說,當 字串表示法相同時。

<?php
// 這會產生一個 Notice,指出陣列無法轉換為字串。
$source = [1, 2, 3, 4];
$filter = [3, 4, [5], 6];
$result = array_diff($source, $filter);

// 然而,這樣是可以的,因為物件可以轉換為字串。
class S {
private
$v;

public function
__construct(string $v) {
$this->v = $v;
}

public function
__toString() {
return
$this->v;
}
}

$source = [new S('a'), new S('b'), new S('c')];
$filter = [new S('b'), new S('c'), new S('d')];

$result = array_diff($source, $filter);

// $result 現在包含一個 S('a') 的執行個體;
?>

若要使用替代的比較函數,請參閱 array_udiff()

注意事項

注意:

此函數僅檢查 n 維陣列的一個維度。當然,您可以透過使用 array_diff($array1[0], $array2[0]); 來檢查更深層的維度。

參見

新增註解

使用者提供的註解 29 個註解

249
nilsandre at gmx dot de
17 年前
同樣地,目前函數的描述具有誤導性。我尋找一個函數,它(在數學上)計算 A - B,或者以不同的方式寫為 A \ B。或者,換句話說,假設

A := {a1, ..., an} 和 B:= {a1, b1, ... , bm}

=> array_diff(A,B) = {a2, ..., an}

array_diff(A,B) 會傳回 A 中所有不是 B 的元素(= A 減去 B)。

我認為您應該在文件中更精確地加入這一點。
69
匿名
18 年前
array_diff 提供了一個方便的方法,可以透過值刪除陣列元素,而無需透過冗長的 foreach 迴圈透過鍵來 unset 它,然後再重新鍵化陣列。

<?php

//傳遞您希望刪除的值和要從中刪除的陣列
function array_delete( $value, $array)
{
$array = array_diff( $array, array($value) );
return
$array;
}
?>
40
james dot PLZNOSPAM at bush dot cc
7 年前
如果您想要一個簡單的方法來顯示任一陣列中但不在兩個陣列中的值,您可以使用這個

<?php
function arrayDiff($A, $B) {
$intersect = array_intersect($A, $B);
return
array_merge(array_diff($A, $intersect), array_diff($B, $intersect));
}
?>

如果您想要考慮鍵,請改用 array_diff_assoc();如果您想要移除空值,請使用 array_filter()。
9
wes dot melton at gmail dot com
7 年前
請務必注意,array_diff() 對於較大的陣列來說不是一個快速或節省記憶體的函數。

以我的經驗,當我發現自己在大型陣列(50 個以上的鍵/值對)上執行 array_diff() 時,我幾乎總是意識到我正從錯誤的角度處理問題。

通常,當我重新調整問題以避免需要 array_diff(),尤其是在較大的數據集上時,我會發現效能顯著提升和優化。
8
Al Amin Chayan (mail at chayan dot me)
4 年前
<?php
/**
* 檢查一個陣列是否為另一個陣列的子集
*
* @param array $subset
* @param array $set
* @return bool
*/
function is_subset(array $subset, array $set): bool {
return (bool)!
array_diff($subset, $set);
}

$u = [1, 5, 6, 8, 10];
$a = [1, 5];
$b = [6, 7];

var_dump(is_subset($a, $u)); // true
var_dump(is_subset($b, $u)); // false
2
xmgr2 at protonmail dot com
2 個月前
這個描述乍看之下有點模糊,人們可能會認為 array_diff 函數會返回 *所有* 給定陣列之間的差異(這正是我實際在尋找的,這也是為什麼我驚訝於範例程式碼的結果不包含「yellow」的原因)。

然而,我寫了一個簡潔的單行程式碼來計算所有給定陣列之間的差異

<?php
# 返回一個包含所有給定陣列中獨有值的陣列
function array_unique_values(...$arrays) {
return
array_keys(array_filter(array_count_values(array_merge(...$arrays)), fn($count) => $count === 1));
}

# 範例:
$array1 = ['a', 'b', 'c', 'd'];
$array2 = ['a', 'b', 'x', 'y'];
$array3 = ['a', '1', 'y', 'z'];

print_r(array_unique_values($array1, $array2, $array3));
?>

結果
陣列
(
[0] => c
[1] => d
[2] => x
[3] => 1
[4] => z
)
43
Jeppe Utzon
12 年前
如果你只需要知道兩個陣列的值是否完全相同(不論鍵和順序),那麼可以不用 array_diff,這是一個簡單的方法

<?php

function identical_values( $arrayA , $arrayB ) {

sort( $arrayA );
sort( $arrayB );

return
$arrayA == $arrayB;
}

// 範例:

$array1 = array( "red" , "green" , "blue" );
$array2 = array( "green" , "red" , "blue" );
$array3 = array( "red" , "green" , "blue" , "yellow" );
$array4 = array( "red" , "yellow" , "blue" );
$array5 = array( "x" => "red" , "y" => "green" , "z" => "blue" );

identical_values( $array1 , $array2 ); // true
identical_values( $array1 , $array3 ); // false
identical_values( $array1 , $array4 ); // false
identical_values( $array1 , $array5 ); // true

?>

只有當兩個陣列包含相同數量的數值,且一個陣列中的每個數值在另一個陣列中都有完全相同的複本時,該函數才會返回 true。其他情況都會返回 false。

我評估兩個陣列是否包含(所有)相同數值的替代方法

<?php

sort
($a); $sort(b); return $a == $b;

?>

可能比這個 array_diff 方法快一點(10-20%)

<?php

return ( count( $a ) == count( $b ) && !array_diff( $a , $b ) ? true : false );

?>

但僅當兩個陣列包含相同數量的數值時,且僅在某些情況下。否則,由於在 array_diff() 之前使用了 count() 測試,後者的方法會快得多。

此外,如果兩個陣列包含不同數量的數值,那麼哪種方法更快將取決於是否需要對兩個陣列進行排序。兩次 sort() 比一次 array_diff() 慢一點,但如果其中一個陣列已經排序,那麼你只需要對另一個陣列進行排序,這將幾乎比 array_diff() 快兩倍。

基本上:2 次 sort() 比 1 次 array_diff() 慢,而 1 次 array_diff() 比 1 次 sort() 慢。
24
firegun at terra dot com dot br
15 年前
大家好,

我一直在尋找一個適用於遞迴陣列的 array_diff,我試過 ottodenn at gmail dot com 的函數,但對我的情況來說它沒有達到預期的效果,所以我自己寫了一個。我沒有對此進行廣泛的測試,但我會解釋我的情況,它在這個情況下運作良好:D

我們有 2 個這樣的陣列

<?php
$aArray1
['marcie'] = array('banana' => 1, 'orange' => 1, 'pasta' => 1);
$aArray1['kenji'] = array('apple' => 1, 'pie' => 1, 'pasta' => 1);

$aArray2['marcie'] = array('banana' => 1, 'orange' => 1);
?>

與 array_diff 一樣,此函數返回 aArray1 中存在但不在 aArray2 中的所有項目,因此我們應該預期的結果是

<?php
$aDiff
['marcie'] = array('pasta' => 1);
$aDiff['kenji'] = array('apple' => 1, 'pie' => 1, 'pasta' => 1);
?>

好的,現在是一些關於此函數的註解
- 與 PHP array_diff 不同,此函數不使用 === 運算符,而是使用 ==,因此 0 等於 '0' 或 false,但這可以更改而沒有任何影響。
- 此函數會檢查陣列的鍵,array_diff 僅比較數值。

我真的希望這能幫助到某些人,就像我從一些使用者的經驗中獲得很多幫助一樣。(只是請再次確認它是否適用於您的情況,如同我說的,我只是針對我提出的情境進行測試)

<?php
function arrayRecursiveDiff($aArray1, $aArray2) {
$aReturn = array();

foreach (
$aArray1 as $mKey => $mValue) {
if (
array_key_exists($mKey, $aArray2)) {
if (
is_array($mValue)) {
$aRecursiveDiff = arrayRecursiveDiff($mValue, $aArray2[$mKey]);
if (
count($aRecursiveDiff)) { $aReturn[$mKey] = $aRecursiveDiff; }
} else {
if (
$mValue != $aArray2[$mKey]) {
$aReturn[$mKey] = $mValue;
}
}
} else {
$aReturn[$mKey] = $mValue;
}
}

return
$aReturn;
}
?>
26
SeanECoates at !donotspam!yahoo dot ca
23 年前
我剛發現 array_diff() 的一個非常好用的地方。當讀取一個目錄(opendir;readdir)時,我「很少」希望我正在建立的檔案陣列中包含「.」或「..」。這是一個簡單的方法來移除它們

<?php
$someFiles
= array();
$dp = opendir("/some/dir");
while(
$someFiles[] = readdir($dp));
closedir($dp);

$removeDirs = array(".","..");
$someFiles = array_diff($someFiles, $removeDirs);

foreach(
$someFiles AS $thisFile) echo $thisFile."\n";
?>

S
4
Prakashgun
6 年前
如果第一個陣列中出現重複的值,也會被包含進來。在輸出中可以看到 "blue" 出現了兩次。

<?php

$array1
= array("a" => "green", "red", "blue", "red", "blue");
$array2 = array("b" => "green", "yellow", "red");
$result = array_diff($array1, $array2);

print_r($result);

//輸出
//Array ( [1] => blue [3] => blue )
14
merlyn dot tgz at gmail dot com
12 年前
array_diff 有更快的實現方式,但有一些限制。如果您需要比較兩個整數或字串陣列,可以使用這樣的函式

public static function arrayDiffEmulation($arrayFrom, $arrayAgainst)
{
$arrayAgainst = array_flip($arrayAgainst);

foreach ($arrayFrom as $key => $value) {
if(isset($arrayAgainst[$value])) {
unset($arrayFrom[$key]);
}
}

return $arrayFrom;
}

它比 array_diff 快約 10 倍

php > $t = microtime(true);$a = range(0,25000); $b = range(15000,500000); $c = array_diff($a, $b);echo microtime(true) - $t;
4.4335179328918
php > $t = microtime(true);$a = range(0,25000); $b = range(15000,500000); $c = arrayDiffEmulation($a, $b);echo microtime(true) - $t;
0.37219095230103
8
Anonymous
9 年前
我一直想要類似這樣的東西,以避免列出專案目錄中所有您想要排除的檔案和資料夾。

function array_preg_diff($a, $p) {
foreach ($a as $i => $v)
if (preg_match($p, $v))
unset($a[$i]);
return $a;
}

$relevantFiles = array_preg_diff(scandir('somedir'), '/^\./');

而不是

$relevantFiles = array_diff(scandir('somedir'), array('.', '..', '.idea', '.project));
3
Tim Trefren
16 年前
這是 array_diff 的一個小包裝函式 - 我發現自己需要遍歷編輯過的陣列,而且我不需要原始的鍵值來做任何事情。

<?php
function arrayDiff($array1, $array2){
# 這個 array_diff 的包裝函式會重新索引返回的陣列
$valid_array = array_diff($array1,$array2);

# 重新實例化 $array1 變數
$array1 = array();

# 迴圈遍歷驗證後的陣列,並將元素移動到 $array1
# 這是必要的,因為 array_diff 函式返回的陣列會保留其原始的鍵值
foreach ($valid_array as $valid){
$array1[] = $valid;
}
return
$array1;
}
?>
3
merlinyoda at dorproject dot net
16 年前
正如 kitchin 在 2007 年 6 月 19 日 03:49 的評論以及 nilsandre 在 2007 年 7 月 17 日 10:45 的評論中所提到的,如果您不是從集合論的角度來思考,array_diff 的行為可能會違反直覺。

array_diff() 返回的是陣列 A 中存在於陣列 B 中的元素的*數學*差(又名減法),*而不是*陣列之間不同的元素(即那些存在於 A 或 B 中,但不在 A 和 B 中的元素)。

繪製一個文氏圖或尤拉圖可能有助於視覺化...

至於返回您可能期望的函式,這裡有一個

<?php
function array_xor ($array_a, $array_b) {
$union_array = array_merge($array_a, $array_b);
$intersect_array = array_intersect($array_a, $array_b);
return
array_diff($union_array, $intersect_array)
}
?>
5
Anonymous
21 年前
從頁面中
注意:請注意,此函式僅檢查 n 維陣列的一個維度。當然,您可以透過使用 array_diff($array1[0], $array2[0]); 來檢查更深的維度。

我找到一種方法來繞過這個限制。我有 2 個由陣列組成的陣列。
我想要從第一個陣列中提取所有在第二個陣列中找不到的陣列。所以我使用了 serialize() 函式

<?php
function my_serialize(&$arr,$pos){
$arr = serialize($arr);
}

function
my_unserialize(&$arr,$pos){
$arr = unserialize($arr);
}

// 建立一個副本
$first_array_s = $first_array;
$second_array_s = $second_array;

// 序列化所有子陣列
array_walk($first_array_s,'my_serialize');
array_walk($second_array_s,'my_serialize');

// 對序列化版本執行 array_diff
$diff = array_diff($first_array_s,$second_array_s);

// 反序列化結果
array_walk($diff,'my_unserialize');

// 您成功了!
print_r($diff);
?>
1
emeka dot echeruo at gmail dot com
8 年前
重新提交... 這次的更新考慮了比較的問題
計算所有陣列的差異
<?php

/**
* array_diffs — 計算所有陣列的差異
*
* @param array
*
* array1 - 作為比較基礎的陣列
* array2 - 作為比較基礎的陣列
* array(n) - 更多作為比較基礎的陣列
*
* @return array 傳回所有陣列中,無法在其他陣列中找到匹配項的條目。
*/

function array_diffs() {
$count = func_num_args();
if(
$count < 2) {
trigger_error('必須提供至少 2 個陣列進行比較。');
}
$check = array();
$out = array();
//解決比較問題
$func = function($a, $b) {
$dbl = function($i, $d) {
$e = 0.00001;
if(
abs($i-$d) < $e) {
return
true;
}
return
false;
};
if((
gettype($a) == 'integer' && gettype($b['value']) == 'double') || (gettype($a) == 'double' && gettype($b['value']) == 'integer')) {
if((
gettype($a) == 'integer' && $dbl((double) $a, $b['value'])) || (gettype($b['value']) == 'integer' && $dbl((double) $b['value'], $a))) {
return
true;
}
} elseif((
gettype($a) == 'double') && (gettype($b['value']) == 'double')) {
return
$dbl($a,$b['value']);
} elseif(
$a == $b['value']) {
return
true;
}
return
false;
};
for(
$i = 0; $i < $count; $i++) {
if(!
is_array(func_get_arg($i))) {
trigger_error('參數必須以陣列形式傳遞。');
}
foreach(
func_get_arg($i) as $key => $value) {
if(
is_numeric($key) && is_string($value)) {
if(
array_key_exists($value, $check) && $func($value, $check[$value])) {
$check[$value]['count'] = $check[$value]['count'] + 1;
} else {
$check[$value]['value'] = $value;
$check[$value]['count'] = 1;
}
} elseif(
is_numeric($key) && (is_bool($value) || is_null($value) || is_numeric($value) || is_object($value) || is_resource($value))) {
$update = false;
foreach(
$check as $check_key => $check_value) {
if(
is_numeric($key) && (is_bool($check_value['value']) || is_null($check_value['value']) || is_numeric($check_value['value']) || is_object($check_value['value']) || is_resource($check_value['value'])) && $func($value, $check_value)) {
$update = true;
$check[$check_key]['count'] = $check[$check_key]['count'] + 1;
}
}
if(!
$update) {
$check[] = array('value' => $value, 'count' => 1);
}
} else {
if(
array_key_exists($key, $check) && $func($value, $check[$key])) {
$check[$key]['count'] = $check[$key]['count'] + 1;
} else {
$check[$key]['value'] = $value;
$check[$key]['count'] = 1;
}
}
}
}
foreach(
$check as $check_key => $check_value) {
if(
$check_value['count'] == 1) {
for (
$i = 0; $i < $count; $i++) {
foreach(
func_get_arg($i) as $key => $value) {
if(
is_numeric($key) && is_string($value) && ($value == (string) $check_key)) {
$out[$i][$key] = $value;
} elseif(
is_numeric($key) && ($check_value['value'] == $value)) {
$out[$i][$key] = $value;
} elseif(
is_string($key) && ($check_value['value'] == $value)) {
$out[$i][$key] = $value;
}
}
}
}
}
return
$out;
}

?>
3
Simon Riget at paragi.dk
18 年前
一個簡單的多維陣列差異比較函式。

<?php
function arr_diff($a1,$a2){
foreach(
$a1 as $k=>$v){
unset(
$dv);
if(
is_int($k)){
// 比較值
if(array_search($v,$a2)===false) $dv=$v;
else if(
is_array($v)) $dv=arr_diff($v,$a2[$k]);
if(
$dv) $diff[]=$dv;
}else{
// 比較非整數鍵值
if(!$a2[$k]) $dv=$v;
else if(
is_array($v)) $dv=arr_diff($v,$a2[$k]);
if(
$dv) $diff[$k]=$dv;
}
}
return
$diff;
}
?>

這個函式符合我目前的需求,但我相信它還可以改進。
3
vojtech dot hordejcuk at gmail dot com
15 年前
基於某人的程式碼,我創建了以下函式,用於建立類似 HTML diff 的東西。我希望它會很有用。

<?php
private function diff ($old, $new)
{
$old = preg_replace ('/ +/', ' ', $old);
$new = preg_replace ('/ +/', ' ', $new);

$lo = explode ("\n", trim ($old) . "\n");
$ln = explode ("\n", trim ($new) . "\n");
$size = max (count ($lo), count ($ln));

$equ = array_intersect ($lo, $ln);
$ins = array_diff ($ln, $lo);
$del = array_diff ($lo, $ln);

$out = '';

for (
$i = 0; $i < $size; $i++)
{
if (isset (
$del [$i]))
{
$out .= '<p><del>' . $del [$i] . '</del></p>';
}

if (isset (
$equ [$i]))
{
$out .= '<p>' . $equ [$i] . '</p>';
}

if (isset (
$ins [$i]))
{
$out .= '<p><ins>' . $ins [$i] . '</ins></p>';
}
}

return
$out;
}
?>
2
emeka at echeruo at gmail dot com
8 年前
重新提交... 這次的更新考慮了比較的問題

計算所有陣列的差異

<?php

/**
* array_diffs — Computes the difference of all the arrays
*
* @param array
*
* array1 - The array to compare from and against
* array2 - The array to compare from and against
* array(n) - More arrays to compare from and against
*
* @return array Returns all the arrays that do contains entries that cannot be matched in any of the arrays.
*/

function array_diffs() {
$count = func_num_args();
if(
$count < 2) {
trigger_error('Must provide at least 2 arrays for comparison.');
}
$check = array();
$out = array();
//resolve comparison issues in PHP
$func = function($a, $b) {
if(
gettype($a) == 'integer' && gettype($b['value']) == 'double' || gettype($a) == 'double' && gettype($b['value']) == 'integer') {
if(
gettype($a) == 'integer') {
if((double)
$a == $b['value']) {
return
true;
}
} else {
if((double)
$b['value'] == $a) {
return
true;
}
}
} elseif(
gettype($a) == 'double' && gettype($b['value']) == 'double') {
$epsilon = 0.00001;
if(
abs($a - $b['value']) < $epsilon) {
return
true;
}
} else {
if(
$a == $b['value']) {
return
true;
}
}
return
false;
};
for (
$i = 0; $i < $count; $i++) {
if(!
is_array(func_get_arg($i))) {
trigger_error('Parameters must be passed as arrays.');
}
foreach(
func_get_arg($i) as $key => $value) {
if(
is_numeric($key) && is_string($value)) {
if(
array_key_exists($value, $check) && $func($value, $check[$value])) {
$check[$value]['count'] = $check[$value]['count'] + 1;
} else {
$check[$value]['value'] = $value;
$check[$value]['count'] = 1;
}
} elseif(
is_numeric($key) && (is_bool($value) || is_null($value) || is_numeric($value) || is_object($value) || is_resource($value))) {
$update = false;
foreach(
$check as $check_key => $check_value) {
if(
is_numeric($key) && (is_bool($check_value['value']) || is_null($check_value['value']) || is_numeric($check_value['value']) || is_object($check_value['value']) || is_resource($check_value['value']))) {
if(
$func($value, $check_value)) {
$update = true;
$check[$check_key]['count'] = $check[$check_key]['count'] + 1;
}
}
}
if(!
$update) {
$check[] = array('value' => $value, 'count' => 1);
}
} else {
if(
array_key_exists($key, $check) && $func($value, $check[$key])) {
$check[$key]['count'] = $check[$key]['count'] + 1;
} else {
$check[$key]['value'] = $value;
$check[$key]['count'] = 1;
}
}
}
}
foreach(
$check as $check_key => $check_value) {
if(
$check_value['count'] == 1) {
for (
$i = 0; $i < $count; $i++) {
foreach(
func_get_arg($i) as $key => $value) {
if(
is_numeric($key) && is_string($value)) {
if(
$value == (string) $check_key) {
$out[$i][$key] = $value;
}
} elseif(
is_numeric($key) && (is_bool($value) || is_null($value) || is_numeric($value) || is_object($value) || is_resource($value))) {
if(
is_numeric($key) && (is_bool($check_value['value']) || is_null($check_value['value']) || is_numeric($check_value['value']) || is_object($check_value['value']) || is_resource($check_value['value']))) {
if(
$check_value['value'] == $value) {
$out[$i][$key] = $value;
}
}
} else {
if(
$key == $check_key) {
$out[$i][$key] = $value;
}
}
}
}
}
}
return
$out;
}

?>
2
javierchinapequeno at yahoo dot es
13 年前
嗨,我想給所有需要使用此函式比較兩個具有大量元素的陣列的人一些建議。您應該先對兩個陣列進行排序,然後再進行比較,這樣會更快。
謝謝
2
wrey75 at gmail dot com
10 年前
差異僅在第一層進行。如果要比較 2 個陣列,可以使用 https://gist.github.com/wrey75/c631f6fe9c975354aec7 提供的程式碼(包括一個具有修補陣列函式的類別)。

這是基本函式

function my_array_diff($arr1, $arr2) {
$diff = array();

// 檢查相似性
foreach( $arr1 as $k1=>$v1 ){
if( isset( $arr2[$k1]) ){
$v2 = $arr2[$k1];
if( is_array($v1) && is_array($v2) ){
// 2 個陣列:繼續進行...
// .. 並解釋它是一個更新!
$changes = self::diff($v1, $v2);
if( count($changes) > 0 ){
// 如果沒有變更,則直接忽略
$diff[$k1] = array('upd' => $changes);
}
unset($arr2[$k1]); // 別忘了
}
else if( $v2 === $v1 ){
// 在第二個陣列中取消設定該值
// 用於「剩餘」
unset( $arr2[$k1] );
}
else {
// 不管是不是陣列。
$diff[$k1] = array( 'old' => $v1, 'new'=>$v2 );
unset( $arr2[$k1] );
}
}
else {
// 移除資訊
$diff[$k1] = array( 'old' => $v1 );
}
}

// 現在,檢查 $arr2 中的新內容
reset( $arr2 ); // 別爭論說它是不必要的 (即使我相信你)
foreach( $arr2 as $k=>$v ){
// 好吧,我的朋友,這很愚蠢
$diff[$k] = array( 'new' => $v );
}
return $diff;
}
2
gilthans at NOgmailSPAM dot com
17 年前
我需要一個函式,只刪除元素在第二個陣列中出現的次數。換句話說,如果您有陣列 (1, 1, 2) 和陣列 (1),則傳回值應為陣列 (1, 2)。
所以我建立了這個函式

<?php
function array_diff_once(){
if((
$args = func_num_args()) < 2)
return
false;
$arr1 = func_get_arg(0);
$arr2 = func_get_arg(1);
if(!
is_array($arr1) || !is_array($arr2))
return
false;
foreach(
$arr2 as $remove){
foreach(
$arr1 as $k=>$v){
if((string)
$v === (string)$remove){ //注意:如果您需要 diff 嚴格比較,請移除這兩個 '(string)'
unset($arr1[$k]);
break;
//這幾乎是與真正的 array_diff 唯一的區別:P
}
}
}
// 處理 2 個以上的引數
$c = $args;
while(
$c > 2){
$c--;
$arr1 = array_diff_once($arr1, func_get_arg($args-$c+1));
}
return
$arr1;
}
$arr1 = Array("blue", "four"=>4, "color"=>"red", "blue", "green", "green", "name"=>"jon", "green");
$arr2 = Array("4", "red", "blue", "green");
print_r(array_diff_once($arr1, $arr2));
?>
這會列印出
Array ( [1] => blue [3] => green [name] => jon [4] => green )

請注意,它是從左到右刪除元素,與您可能預期的相反;在我的例子中,元素的順序並不重要。修復這個問題需要稍作修改。
2
Anonymous
15 年前
嗨!
我努力尋找一個問題的解決方案,我將在這裡解釋,並且在閱讀了所有的陣列函式和可能性之後,我不得不創建我認為應該存在於下一個 PHP 版本中的東西。

我需要的是某種差異比較,但需要處理兩個陣列並同時修改它們,而不是傳回一個陣列作為差異本身的結果。

因此,作為一個範例

A = 1,2,3
B = 2,3,4

不應該是

C = 1,4

而是

A = 1
B = 4

所以基本上,我想要刪除兩個陣列中的重複項。

現在,我有一些動作要做,而且我知道該對哪個陣列的值執行哪個動作。
使用一般的 DIFF,我做不到,因為如果我有一個像 C=1,4 這樣的陣列,我不知道該對 1 或 4 執行 Action_A,但我很清楚 A 中的所有內容都會執行 Action_A,而 B 中的所有內容都會執行 Action_B。 4 也會發生同樣的情況,我不知道要套用哪個動作...

所以我創建了這個

<?php
function array_diff_ORG_NEW(&$org, &$new, $type='VALUES'){
switch(
$type){
case
'VALUES':
$int = array_values(array_intersect($org, $new)); //C = A ^ B
$org = array_values(array_diff($org, $int)); //A' = A - C
$new= array_values(array_diff($new, $int)); //B' = B - C
break;
case
'KEYS':
$int = array_values(array_intersect_key($org, $new)); //C = A ^ B
$org = array_values(array_diff_key($org, $int)); //A' = A - C
$new= array_values(array_diff_key($new, $int)); //B' = B - C
break;
}
}
?>

這個可愛的程式碼,透過參考方式運作,並修改陣列,刪除兩者的重複項,並保留非重複項的完整性。

所以對此的呼叫會像這樣

<?php
$original
= array(1,2,3);
$new = array(2,3,4);

array_diff_ORG_NEW($original, $new, 'VALUES');
?>

然後,在這裡,我將擁有我想要的陣列

$original = 1
$new = 4

現在,我為什麼要精確地使用它呢?

想像一下,您有一些「事件」,而當您建立事件時所選擇的一些使用者可以「看到」您建立的此事件。因此,您會與某些使用者「分享」此事件。好嗎?

假設您建立了一個 Event_A,並與使用者 1,2,3 分享。

現在您想要修改該事件,並且決定修改要分享的使用者。假設您將其變更為使用者 2,3,4。

(數字是使用者 ID)。

因此,您可以在要修改時管理,使其具有 DDBB 中的 ID 陣列 ($original),然後,再有一個包含修改後要分享的使用者 ID 的陣列 ($new)。您必須從 DDBB 中刪除哪些,以及您必須插入哪些?

如果您執行簡單的差異或其他方式,您會得到類似 C=1,4 的東西。
您不知道要插入或刪除哪一個。

但是,透過這種方式,您可以知道,這就是為什麼

- 保留在 $original 中的內容,是從一開始就不存在於 $new 中的內容。因此,您知道 $original 內的所有內容,都必須從 DDBB 中刪除,因為您在修改過程中執行的是取消選擇保留在 $original 中的那些使用者。
- 保留在 $new 中的內容,是從一開始就不存在於 $original 中的內容。這表示在修改過程中,您新增了一些新使用者。而且這些必須插入 DDBB。因此,$new 中保留的所有內容都必須插入 DDBB。

結論

- 剩餘在 $original 中的 --> 從資料庫中刪除。
- 剩餘在 $new 中的 --> 插入資料庫中。

就這樣!

我希望您覺得它有用,並且我鼓勵 PHP「開發者」,在不久的將來,原生新增類似這樣的功能,因為我確信我不是第一個需要這種功能的人。

祝大家安好,

Light。
1
eugeny dot yakimovitch at gmail dot com
13 年前
請注意,array_diff 並不等於

<?php
function fullArrayDiff($left, $right)
{
return
array_diff(array_merge($left, $right), array_intersect($left, $right));
}
?>

因為它是集合論中的補集,如

http://en.wikipedia.org/wiki/Complement_(set_theory)
1
Viking Coder
18 年前
對於任何想要雙向 array_diff 的人 - rudigier at noxx dot at 提到。請記住,array_diff 會提供您第一個陣列中所有不在後續陣列中的內容。

$array1=array('blue','red','green');
$array2=array('blue','yellow','green');

array_merge(array_diff($array1, $array2),array_diff($array2, $array1));

結果
------
陣列
(
[0] => red
[1] => yellow
)
1
Sbastien
一年前
我使用 array_diff() 和 array_intersect() 來檢查 CSV 檔案在處理前的完整性

<?php

$header
= fgetcsv($stream, ...$csv_options); // ['id', 'name', 'sex']

$awaited = ['id', 'name', 'email']; // 我需要在 CSV 中的標頭欄

$present = array_intersect($header, $awaited); // ['id', 'name']

if (count($present) < count($awaited)) { // 2 < 3 => true, 問題!
$missing = array_diff($present, $awaited); // ['email']
$missing = join(', ', $missing);
echo
"遺失的欄: {$missing}\r\n";
}
0
Anonymous
9 年前
如果您使用類似以下陣列的內容,而沒有得到 count(array_diff($a1,$a2))>0 的結果,則應改用 php.net/array_diff_assoc 函式。

$a1 = Array
(
[0] => id
[1] => id_1
[2] => id_2
)

$a2 = Array
(
[0] => id
[1] => id_2
[2] => id_1
)
-1
ds2u at the hotmail dot com
21 年前
是的,您可以使用以下方法來擺脫間隙/遺失的索引鍵

<?php
$result
= array_values(array_diff($array1,$array2));
?>

但是,若要捨棄空白空間(實際上是換行符號)的儲存,這些空白空間在從檔案讀取時會產生惱人的索引,只需使用差異即可

<?php
$array
= array ();
$array[0] = "\n";
$result = array_diff($result,$array);
?>

dst
-2
j dot j dot d dot mol at ewi dot tudelft dot nl
19 年前
這是一些取得兩個陣列差異的程式碼。它允許自訂修改,例如以特定字串作為前綴(如所示)或自訂比較函式。

<?php
// 以 O(n log n) 的時間複雜度回傳 $all 中所有不在 $used 中的元素。
// $all 中的元素會加上 $prefix_all 前綴。
// $used 中的元素會加上 $prefix_used 前綴。
function filter_unused( $all, $used, $prefix_all = "", $prefix_used = "" ) {
$unused = array();

// 排序時不需要前綴
sort( $all );
sort( $used );

$a = 0;
$u = 0;

$maxa = sizeof($all)-1;
$maxu = sizeof($used)-1;

while(
true ) {
if(
$a > $maxa ) {
// 完成;$used 中剩餘的元素不在 $all 中
break;
}
if(
$u > $maxu ) {
// $all 中剩餘的元素未使用
for( ; $a <= $maxa; $a++ ) {
$unused[] = $all[$a];
}
break;
}

if(
$prefix_all.$all[$a] > $prefix_used.$used[$u] ) {
// $used[$u] 不在 $all 中?
$u++;
continue;
}

if(
$prefix_all.$all[$a] == $prefix_used.$used[$u] ) {
// $all[$a] 已被使用
$a++;
$u++;
continue;
}

$unused[] = $all[$a];

$a++;
}

return
$unused;
}
?>
To Top