PHP Conference Japan 2024

array_udiff

(PHP 5, PHP 7, PHP 8)

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

描述

array_udiff(数组 $array, 数组 ...$arrays, 可调用 $value_compare_func): 数组

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

参数

array

第一个数组。

arrays

要比较的数组。

value_compare_func

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

回调(混合 $a, 混合 $b): 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'), "清洁GoogleGuy的公寓.");
$myCalendar->bookAppointment(new DateTime('Wednesday this week'), "去滑雪之旅.");
$myCalendar->bookAppointment(new DateTime('Friday this week'), "修复有bug的代码.");

// 通过比较$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] 进行比较。如果回调函数对任何比较返回零,则 $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 ) )

需要注意的是,比较函数的两个参数与 array1 和 array2 不对应。这就是为什么必须在其中包含逻辑来处理这两个参数中的任何一个都可能指向更复杂的 employee 数组的原因。(我以艰难的方式发现了这一点。)
adam dot jorgensen dot za at gmail dot com
16 年前
此函数未说明,它还会将 array1 与自身进行比较,从而删除任何重复的值……
b4301775 at klzlk dot com
13 年前
使用 array_udiff 进行多维 diff 的快速示例

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

<?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);
?>

输出

数组
(
[0] => 数组
(
[0] => Bob
[1] => 42
)

[2] => 数组
(
[0] => Frank
[1] => 39
)

)
1

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

以下是使用太空船运算符的示例 #1。

<?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'));
?>

输出结果是
数组
(
[0] => stdClass 对象
(
[width] => 11
[height] => 3
)

[1] => stdClass 对象
(
[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 等任何具有类似功能的函数,这些函数都接受回调函数作为参数)的不区分大小写的版本的非常简单的方法

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