通过比较特定共享属性/列的值,保留两个对象数组中的相交对象

发布于 2024-10-06 01:45:29 字数 1368 浏览 2 评论 0原文

我正在寻找一种比较 PHP 中对象数组的简洁方法。我知道我可以只检查大小相等的数组,然后循环遍历一个数组,查找第二个数组中的每个对象,但我认为使用一个或多个数组比较函数会更好。

我已经测试了几个对象数组,我遇到的主要问题是数组比较函数坚持将元素作为字符串进行比较,如下所示:

class Foo{
    public $pk=NULL;
    function __construct($pk){
        $this->pk=$pk;
    }

    function __toString(){
        return (string)$this->pk;//even an integer must be cast or array_intersect fails
    }
}

for($i=1;$i<7;$i++){
    $arr1[]=new Foo($i);
}
for($i=2;$i<5;$i++){
    $arr2[]=new Foo($i);
}

$int=array_intersect($arr1,$arr2);
print_r($int);

outputs

Array
(
[1] => Foo Object
    (
        [pk] => 2
    )

[2] => Foo Object
    (
        [pk] => 3
    )

[3] => Foo Object
    (
        [pk] => 4
    )

如果对象具有__toString() 方法,并且如果这些 __toString() 方法返回唯一标识符并且从不返回 ''

但如果情况并非如此,会发生什么情况,比如对于这样的对象:

class Bar{
    public $pk=NULL;
    function __construct($pk){
        $this->pk=$pk;
    }

    function __toString(){
        return 'I like candy.';//same for all instances
    }

    function Equals(self $other){
        return ($this->pk==$other->pk);
    }

}

是否可以执行 array_uintersect($arr1,$arr2,$somecallback) 来强制使用 Foo::等于()?据我所知,到 string 的转换发生在调用回调之前。

有什么想法可以解决这个问题吗?

I'm looking for a succinct way of comparing arrays of objects in PHP. I know I could just check for equal sized arrays and then loop through one array looking for each object in the second array, but I thought it would be nicer to use one or more of the array comparison functions.

I've tested a couple arrays of objects and the main problem I'm coming up against is that the array comparison functions insist on comparing elements as strings, like this:

class Foo{
    public $pk=NULL;
    function __construct($pk){
        $this->pk=$pk;
    }

    function __toString(){
        return (string)$this->pk;//even an integer must be cast or array_intersect fails
    }
}

for($i=1;$i<7;$i++){
    $arr1[]=new Foo($i);
}
for($i=2;$i<5;$i++){
    $arr2[]=new Foo($i);
}

$int=array_intersect($arr1,$arr2);
print_r($int);

outputs

Array
(
[1] => Foo Object
    (
        [pk] => 2
    )

[2] => Foo Object
    (
        [pk] => 3
    )

[3] => Foo Object
    (
        [pk] => 4
    )

)

That's fine if the objects have __toString() methods and if those __toString() methods return a unique identifier and never ''.

But what happens if that's not the case, say for an object like this:

class Bar{
    public $pk=NULL;
    function __construct($pk){
        $this->pk=$pk;
    }

    function __toString(){
        return 'I like candy.';//same for all instances
    }

    function Equals(self $other){
        return ($this->pk==$other->pk);
    }

}

Is it possible to do array_uintersect($arr1,$arr2,$somecallback) that forces the use of Foo::Equals()? From what I can see the conversion to string happens before the callback is called.

Any ideas how to get around this?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

明天过后 2024-10-13 01:45:29

是的,您可以使用 array_uintersect 来实现此目的。

一些示例代码:

class Fos {
    public $a = 0;
    function __construct($a) {
        $this->a = $a;
    }
    static function compare($a, $b) {
        if ($a->a == $b->a) return 0;
        if ($a->a > $b->a) return 1;
        if ($a->a < $b->a) return -1;
    }
}

$fos1 = array();
$fos2 = array();

for ($i = 1; $i < 10; $i++) {
    $fos1[] = new Fos($i);
}

for ($i = 8; $i < 18; $i++) {
    $fos2[] = new Fos($i);
}

$fosi = array_uintersect($fos1, $fos2, array('Fos','compare'));

Yes, you can use array_uintersect for this.

Some example code:

class Fos {
    public $a = 0;
    function __construct($a) {
        $this->a = $a;
    }
    static function compare($a, $b) {
        if ($a->a == $b->a) return 0;
        if ($a->a > $b->a) return 1;
        if ($a->a < $b->a) return -1;
    }
}

$fos1 = array();
$fos2 = array();

for ($i = 1; $i < 10; $i++) {
    $fos1[] = new Fos($i);
}

for ($i = 8; $i < 18; $i++) {
    $fos2[] = new Fos($i);
}

$fosi = array_uintersect($fos1, $fos2, array('Fos','compare'));
久随 2024-10-13 01:45:29

@kapa 的答案的更现代的等价物可以使用具有箭头函数语法的匿名回调函数和用于返回 3 路比较整数的太空船运算符。 (演示

class Foo {
    public $pk;
    function __construct($v) {
        $this->pk = $v;
    }
}

$foo1 = [];
$foo2 = [];

for ($i = 1; $i < 10; ++$i) {
    $foo1[] = new Foo($i);
}

for ($i = 8; $i < 18; ++$i) {
    $foo2[] = new Foo($i);
}

var_export(
    array_uintersect($foo1, $foo2, fn($a, $b) => $a->pk <=> $b->pk)
);

The more modern equivalent of @kapa's answer can use an anonymous callback function with arrow function syntax and the spaceship operator for returning the 3-way comparison integer. (Demo)

class Foo {
    public $pk;
    function __construct($v) {
        $this->pk = $v;
    }
}

$foo1 = [];
$foo2 = [];

for ($i = 1; $i < 10; ++$i) {
    $foo1[] = new Foo($i);
}

for ($i = 8; $i < 18; ++$i) {
    $foo2[] = new Foo($i);
}

var_export(
    array_uintersect($foo1, $foo2, fn($a, $b) => $a->pk <=> $b->pk)
);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文