我想将一个复杂对象数组与一个id数组进行比较,预期结果是没有列出其id的任何对象的数组。
这听起来像是array_udiff
的完美用例,但是如果没有一些令人困惑的麻烦,我将无法使其正常工作。为了说明我对该功能的问题,下面是一个简化的示例:
class Foo {
public $id;
public function __construct($id) {
$this->id = $id;
}
}
$foos = [new Foo(1), new Foo(2), new Foo(3), new Foo(4)];
$fooIds = [1, 2, 3, 4];
$diff = array_udiff($foos, $fooIds, function ($f, $i){ return $f->id - $i; });
print_r($diff); // expected result: an empty array
// actual result:
// Array
// (
// [1] => Foo Object
// (
// [id] => 2
// )
// )
// Object of class Foo could not be converted to int :11
在我看来,array_udiff
试图在数组元素之间进行某种类型的强制转换。我在文档中没有提到这一点,one question on SO似乎提出了类似的要求,但没有任何答案。我想知道的是:
array_udiff
这样行事?如果我们可以提供任意的回调函数,则这种强制似乎是完全没有必要的,对我而言甚至是无益的。答案 0 :(得分:2)
尽管有点丑陋,但看似最简单的获得所需结果的方法是在比较之前进行类型检查。
<?php
declare(strict_types=1);
error_reporting(-1);
ini_set('display_errors', 'On');
class Foo
{
public $id;
public function __construct($id) {
$this->id = $id;
}
}
$foos = [new Foo(1), new Foo(2), new Foo(3), new Foo(4)];
$fooIds = [1, 2, 3, 4];
$diff = array_udiff($foos, $fooIds, function ($a, $b) {
echo gettype($a), ' <=> ', gettype($b), "\n";
if ($a instanceof Foo && $b instanceof Foo) {
return $a->id <=> $b->id;
}
if ($a instanceof Foo) {
return $a->id <=> $b;
}
if ($b instanceof Foo) {
return $a <=> $b->id;
}
return $a <=> $b;
});
print_r($diff); // expected result: an empty array
答案 1 :(得分:2)
我认为@apokryfos(来自the answer you shared):
在第一个数组和$ b中不会有
$a
从第二个数组。您实际上在功能中拥有的是 比较器,因此,如果您基于比较器对两个数组进行排序(在O(nlogn)
时间内,则可以通过排序联接在O(n)
时间内获得diff) 方式。如果只是成对比较,它将是O(n^2)
,所以我 建议您将回调作为一般的比较器函数 适用于组合的第一和第二个数组
无论如何,我建议使用array_column
和星际飞船运营商一种简单的解决方法:
$diff = array_udiff(array_column($foos, "id"), $fooIds, function ($f, $i){ return $f <=> $i; });
array_column
也适用于PHP 7中的对象
答案 2 :(得分:2)
使用专门用于获取Foo
($f->id
)或非Foo
($f
)的比较值的中间函数:
$val = function($f) {
return $f instanceof Foo ? $f->id : $f;
};
$diff = array_udiff(
$foos,
$fooIds,
function ($f, $i) use ($val) { return $val($f) - $val($i); }
);
或在单个比较功能中:
function ($f, $i) { return ($f instanceof Foo ? $f->id : $f) - ($i instanceof Foo ? $i->id ? $i); }