通过与不同名称的属性相关的值来比较两个对象数组

问题描述 投票:0回答:2

这可能真的很简单,但我似乎无法理解。我有两个对象数组

$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
的对象。有什么干净的解决方案吗?

php arrays object comparison array-difference
2个回答
1
投票

您可能正在寻找 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
测试。


0
投票

就像

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',
  ),
)
© www.soinside.com 2019 - 2024. All rights reserved.