这可能真的很简单,但我似乎无法理解。我有两个对象数组
$a
和 $b
。在 $a
中,我有带有键 email
的对象,在 $b
中,我有带有 user_email
的对象(无法更改,因为它来自 API)。我想要第三个数组 $c
作为输出,其中包含 email == user_email
所在的所有对象。我尝试过像这样使用array_udiff
:
$c = array_udiff($a, $b,
function ($obj_a, $obj_b) {
return $obj_a->email - $obj_b->user_email;
}
);
出于某种原因,$obj_b并不总是像我想象的那样来自数组
$b
的对象。有什么干净的解决方案吗?
您可能正在寻找 array_uintersect。另外,您应该将字符串与 strcmp 进行比较,甚至更好地与 strcasecmp 进行比较。请记住,PHP 将数组元素传递给回调的顺序并不总是与数组的顺序相同。
$a = [(object)['email' => 'a'], (object)['email' => 'b'], (object)['email' => 'c']];
$b = [(object)['user_email' => 'c'], (object)['user_email' => 'a'], (object)['user_email' => 'd']];
$comparer = function($obj_a, $obj_b) {
$email_a = property_exists($obj_a, 'email')
? $obj_a->email
: $obj_a->user_email;
$email_b = property_exists($obj_b, 'email')
? $obj_b->email
: $obj_b->user_email;
return strcasecmp($email_a, $email_b);
};
// only objects with email property
$c = array_uintersect($a, $b, $comparer);
// both objects with email and user_email property
$d = array_merge(
array_uintersect($a, $b, $comparer),
array_uintersect($b, $a, $comparer)
);
如果参数是具体类,则可以将使用
property_exists
测试更改为使用 instanceof
测试。
就像
usort()
函数一样,array_uintersect()
和 array_udiff()
系列函数不能保证回调签名中的 $a
和 $b
参数与第一个和第二个输入数组相关。事实上,这些函数允许超过 2 个输入数组,但回调签名中的参数数量并没有增加。
要解决您遇到的问题,如果第一次尝试的属性访问失败,请使用空合并运算符回退到相反对象的属性。
代码:(演示)
$emails = [
(object) ['email' => 'a'],
(object) ['email' => 'b'],
(object) ['email' => 'c']
];
$userEmails = [
(object) ['user_email' => 'c'],
(object) ['user_email' => 'a'],
(object) ['user_email' => 'd']
];
var_export(
array_udiff(
$emails,
$userEmails,
fn($a, $b) => ($a->email ?? $a->user_email) <=> ($b->email ?? $b->user_email)
)
);
结果:
array (
1 =>
(object) array(
'email' => 'b',
),
)