array_udiff

(PHP 5, PHP 7, PHP 8)

array_udiff使用回调函数进行数据比较来计算数组的差集

说明

array_udiff(array $array, array ...$arrays, callable $value_compare_func): array

使用回调函数进行数据比较来计算数组的差集。这与 array_diff() 不同,后者使用内部函数来比较数据。

参数

array

第一个数组。

arrays

要比较的数组。

value_compare_func

比较函数必须返回一个整数,如果第一个参数分别小于、等于或大于第二个参数,则返回小于零、等于零或大于零。

callback(mixed $a, mixed $b): int
注意

从比较函数返回 *非整数* 值,例如 float,将导致内部将回调的返回值强制转换为 int。因此,像 0.990.1 这样的值都将被强制转换为 0 的整数值,这将比较这些值为相等。

注意

排序回调必须处理来自任何数组的任何值,无论它们最初提供的顺序如何。这是因为每个单独的数组在与其他数组比较之前都会先排序。例如

<?php
$arrayA
= ["string", 1];
$arrayB = [["value" => 1]];
// $item1 和 $item2 可以是 "string"、1 或 ["value" => 1] 中的任何一个
$compareFunc = static function ($item1, $item2) {
$value1 = is_string($item1) ? strlen($item1) : (is_array($item1) ? $item1["value"] : $item1);
$value2 = is_string($item2) ? strlen($item2) : (is_array($item2) ? $item2["value"] : $item2);
return
$value1 <=> $value2;
};
?>

返回值

返回一个数组,包含 array 中所有不在其他任何参数中的值。

范例

范例 #1 使用 stdClass 对象的 array_udiff() 例子

<?php
// 要比较的数组
$array1 = array(new stdClass, new stdClass,
new
stdClass, new stdClass,
);

$array2 = array(
new
stdClass, new stdClass,
);

// 为每个对象设置一些属性
$array1[0]->width = 11; $array1[0]->height = 3;
$array1[1]->width = 7; $array1[1]->height = 1;
$array1[2]->width = 2; $array1[2]->height = 9;
$array1[3]->width = 5; $array1[3]->height = 7;

$array2[0]->width = 7; $array2[0]->height = 5;
$array2[1]->width = 9; $array2[1]->height = 2;

function
compare_by_area($a, $b) {
$areaA = $a->width * $a->height;
$areaB = $b->width * $b->height;

if (
$areaA < $areaB) {
return -
1;
} elseif (
$areaA > $areaB) {
return
1;
} else {
return
0;
}
}

print_r(array_udiff($array1, $array2, 'compare_by_area'));
?>

上面的例子将输出

Array
(
    [0] => stdClass Object
        (
            [width] => 11
            [height] => 3
        )

    [1] => stdClass Object
        (
            [width] => 7
            [height] => 1
        )

)

范例 #2 使用 DateTime 对象的 array_udiff() 例子

<?php
class MyCalendar {
public
$free = array();
public
$booked = array();

public function
__construct($week = 'now') {
$start = new DateTime($week);
$start->modify('Monday this week midnight');
$end = clone $start;
$end->modify('Friday this week midnight');
$interval = new DateInterval('P1D');
foreach (new
DatePeriod($start, $interval, $end) as $freeTime) {
$this->free[] = $freeTime;
}
}

public function
bookAppointment(DateTime $date, $note) {
$this->booked[] = array('date' => $date->modify('midnight'), 'note' => $note);
}

public function
checkAvailability() {
return
array_udiff($this->free, $this->booked, array($this, 'customCompare'));
}

public function
customCompare($free, $booked) {
if (
is_array($free)) $a = $free['date'];
else
$a = $free;
if (
is_array($booked)) $b = $booked['date'];
else
$b = $booked;
if (
$a == $b) {
return
0;
} elseif (
$a > $b) {
return
1;
} else {
return -
1;
}
}
}

// 创建一个用于每周预约的日历
$myCalendar = new MyCalendar;

// 预约本周的一些预约
$myCalendar->bookAppointment(new DateTime('Monday this week'), "Cleaning GoogleGuy's apartment.");
$myCalendar->bookAppointment(new DateTime('Wednesday this week'), "Going on a snowboarding trip.");
$myCalendar->bookAppointment(new DateTime('Friday this week'), "Fixing buggy code.");

// 通过比较 $booked 日期和 $free 日期来检查每天的可用性
echo "本周我在以下几天有空...\n\n";
foreach (
$myCalendar->checkAvailability() as $free) {
echo
$free->format('l'), "\n";
}
echo
"\n\n";
echo
"本周我在以下几天很忙...\n\n";
foreach (
$myCalendar->booked as $booked) {
echo
$booked['date']->format('l'), ": ", $booked['note'], "\n";
}
?>

上面的例子将输出

I'm available on the following days this week...

Tuesday
Thursday


I'm busy on the following days this week...

Monday: Cleaning GoogleGuy's apartment.
Wednesday: Going on a snowboarding trip.
Friday: Fixing buggy code.

笔记

注意: 请注意,此函数仅检查 n 维数组的一维。当然,您可以使用 array_udiff($array1[0], $array2[0], "data_compare_func"); 检查更深的维度。

另请参阅

添加笔记

用户贡献的笔记 9 笔记

Colin
18 年前
我认为这里用类给出的例子过于复杂,无法演示此函数的功能。

array_udiff() 将遍历 array_values($a) 和 array_values($b),并使用传入的回调函数比较每个值。

换句话说,array_udiff() 使用提供的回调函数将 $a[0] 与 $b[0]、$b[1]、$b[2] 和 $b[3] 进行比较。如果回调函数对任何比较返回 0,则 $a[0] 不会出现在 array_udiff() 返回的数组中。然后它将 $a[1] 与 $b[0]、$b[1]、$b[2] 和 $b[3] 进行比较。最后,$a[2] 与 $b[0]、$b[1]、$b[2] 和 $b[3] 进行比较。

例如,compare_ids($a[0], $b[0]) === -5,而 compare_ids($a[1], $b[1]) === 0。因此,$a[1] 不会从 array_udiff() 返回,因为它存在于 $b 中。

<?
$a = array(
array(
'id' => 10,
'name' => 'John',
'color' => 'red',
),
array(
'id' => 20,
'name' => 'Elise',
'color' => 'blue',
),
array(
'id' => 30,
'name' => 'Mark',
'color' => 'red',
),
);

$b = array(
array(
'id' => 15,
'name' => 'Nancy',
'color' => 'black',
),
array(
'id' => 20,
'name' => 'Elise',
'color' => 'blue',
),
array(
'id' => 30,
'name' => 'Mark',
'color' => 'red',
),
array(
'id' => 40,
'name' => 'John',
'color' => 'orange',
),
);

function compare_ids($a, $b)
{
return ($a['id'] - $b['id']);
}
function compare_names($a, $b)
{
return strcmp($a['name'], $b['name']);
}

$ret = array_udiff($a, $b, 'compare_ids');
var_dump($ret);

$ret = array_udiff($b, $a, 'compare_ids');
var_dump($ret);

$ret = array_udiff($a, $b, 'compare_names');
var_dump($ret);
?>

这将返回以下内容。

在第一个返回值中,我们看到 $b 中没有 id 为 10 的条目。
<?
array(1) {
[0]=>
array(3) {
["id"]=>
int(10)
["name"]=>
string(4) "John"
["color"]=>
string(3) "red"
}
}
?>

在第二个返回值中,我们看到 $a 中没有 id 为 15 或 40 的条目。
<?
array(2) {
[0]=>
array(3) {
["id"]=>
int(15)
["name"]=>
string(5) "Nancy"
["color"]=>
string(5) "black"
}
[3]=>
array(3) {
["id"]=>
int(40)
["name"]=>
string(4) "John"
["color"]=>
string(6) "orange"
}
}
?>

在第三个返回值中,我们看到 $a 中的所有名称都存在于 $b 中(即使 $b 中名称为 'John' 的条目不同,匿名函数只比较名称)。
<?
array(0) {
}
?>
napcoder
8 年前
请注意,比较函数也在内部使用,用于对数组进行排序并选择下一轮中要比较的元素。

如果您的比较函数不是真正的比较(即如果元素相等则返回 0,否则返回 1),您将得到意外的结果。
grantwparks at gmail dot com
16 年前
关于“复杂”

我认为要说明的是,array_udiff() 不仅可以用于比较同构数组,如您的示例(并且绝对是最常见的需求),还可以用于比较异构数组。

考虑以下情况

<?php
function compr_1($a, $b) {
$aVal = is_array($a) ? $a['last_name'] : $a;
$bVal = is_array($b) ? $b['last_name'] : $b;
return
strcasecmp($aVal, $bVal);
}

$aEmployees = array(
array(
'last_name' => 'Smith',
'first_name' => 'Joe',
'phone' => '555-1000'),
array(
'last_name' => 'Doe',
'first_name' => 'John',
'phone' => '555-2000'),
array(
'last_name' => 'Flagg',
'first_name' => 'Randall',
'phone' => '666-1000')
);

$aNames = array('Doe', 'Smith', 'Johnson');

$result = array_udiff($aEmployees, $aNames, "compr_1");

print_r($result);
?>

这使我能够获取不在姓名列表中的“员工”。

Array ( [2] => Array ( [last_name] => Flagg [first_name] => Randall [phone] => 666-1000 ) )

需要注意的是,比较函数的两个参数不对应于数组1和数组2。 这就是为什么必须在其中添加逻辑来处理这两个参数可能指向更复杂的员工数组的情况。(我是以这种方式发现的。)
adam dot jorgensen dot za at gmail dot com
15 年前
此函数没有说明,它还会将数组1与自身进行比较,删除所有重复的值...
b4301775 at klzlk dot com
13 年前
使用 array_udiff 执行多维差异的快速示例

返回不在 $arr2 中的 $arr1 的值

<?php
$arr1
= array( array('Bob', 42), array('Phil', 37), array('Frank', 39) );

$arr2 = array( array('Phil', 37), array('Mark', 45) );

$arr3 = array_udiff($arr1, $arr2, create_function(
'$a,$b',
'return strcmp( implode("", $a), implode("", $b) ); ')
);

print_r($arr3);
?>

输出

Array
(
[0] => Array
(
[0] => Bob
[1] => 42
)

[2] => Array
(
[0] => Frank
[1] => 39
)

)
1

希望这能帮助到某人
Jorge Morales (morales2k)
5 年前
我发现这是一个应用 spaceship 运算符的理想场所,但示例中没有使用它。

以下是示例#1,在比较函数中使用 spaceship 运算符。

<?php
// 要比较的数组
$array1 = array(new stdclass, new stdclass,
new
stdclass, new stdclass,
);

$array2 = array(
new
stdclass, new stdclass,
);

// 为每个对象设置一些属性
$array1[0]->width = 11; $array1[0]->height = 3;
$array1[1]->width = 7; $array1[1]->height = 1;
$array1[2]->width = 2; $array1[2]->height = 9;
$array1[3]->width = 5; $array1[3]->height = 7;

$array2[0]->width = 7; $array2[0]->height = 5;
$array2[1]->width = 9; $array2[1]->height = 2;

function
compare_by_area($a, $b) {
$areaA = $a->width * $a->height;
$areaB = $b->width * $b->height;

return
$areaA <=> $areaB;
}

print_r(array_udiff($array1, $array2, 'compare_by_area'));
?>

输出结果为
Array
(
[0] => stdClass Object
(
[width] => 11
[height] => 3
)

[1] => stdClass Object
(
[width] => 7
[height] => 1
)

)

我发现你可以用以下几行代码来替换所有这些代码
if ($areaA < $areaB) {
return -1;
} elseif ($areaA > $areaB) {
return 1;
} else {
return 0;
}

只需使用

return $areaA <=> $areaB;

真棒!
dmhouse at gmail dot com
19 年前
实现 array_diff(或实际上是 array_diff_assoc、array_intersect 或任何这些类似的函数,这些函数具有类似的函数,其中一个参数作为回调函数)的 case-insensitive 版本的非常简单的方法

array_udiff($array1, $array2, 'strcasecmp');

这是可行的,因为 strcasecmp() 会不区分大小写地比较两个字符串,而 array_diff() 会使用 == 运算符比较两个字符串,该运算符区分大小写。
jared
15 年前
请注意,php 会在将值发送到回调函数之前进行字符串转换。
aidan at php dot net
20 年前
此功能现在已在 PEAR 包 PHP_Compat 中实现。

有关在不升级 PHP 版本的情况下使用此函数的更多信息,请访问以下链接

http://pear.php.net/package/PHP_Compat
To Top