2010-05-14 98 views
9

我想知道如何array_intersect对象数组。数组相交为对象数组php

+0

你是什么意思的“对象数组” - 你的意思是一个对象数组? – thetaiko 2010-05-14 13:59:53

+0

是的,那是对象数组。 – 2010-05-14 14:09:13

回答

2

array_intersect()返回包含所有参数中存在的array1的所有值的数组。

那么究竟意味着什么目前在这方面(exacly此功能),我发现php.net我的回答:

Two elements are considered equal if and only if (string) $elem1 === (string) $elem2. In words: when the string representation is the same.

那么你可以不使用它的阵列对象如果你的对象没有实现对字符串的唯一转换。

+4

这是无耻的。至少有三种方法可以将对象转换为字符串。它们可能是一个PHP类并实现__toString,它们可能有一个接受IS_STRING的转换处理程序,它们可能有一个get处理程序,它返回一个可转换为字符串的zval。 – Artefacto 2010-05-14 14:01:05

+0

+1 @Artefacto,用一个使用任意对象和array_intersect()的例子来提交答案。 – Dolph 2010-05-14 14:04:33

+0

如果你的对象没有实现对字符串的唯一转换。 – Svisstack 2010-05-14 14:05:49

1

检查两个对象是否相等的正确方法是使用==。因此:

array_uintersect($arr1, $arr2, function ($a1, $a2) { return $a1 == $a2; }); 
+0

这不起作用.. 你有其他编码吗? – 2010-05-15 12:30:40

+1

你必须更具体。什么不行?有没有错误信息?什么错误信息?输出不是预期的?预期什么?你得到了什么? – Artefacto 2010-05-15 19:19:21

+1

这不起作用,因为array_unintersect需要比较函数返回1,-1或0. 请参阅此处以获取完整说明和示例http://php.net/manual/en/function.array-uintersect。 php#72841 – Tim 2014-12-21 09:23:39

6

不错的toString功能已经实现,被称为连载;)这样

array_map(
    'unserialize', 
    array_intersect(
     array_map(
      'serialize', 
      $obj1 
     ), 
     array_map(
      'serialize', 
      $obj2 
     ) 
    ) 
); 

会做的工作,例如提到更高的不工作“导致array_intersect工作的只有字符串作为人也提到

+0

优秀的黑客。完美的作品:) – yitwail 2012-04-07 23:30:12

+0

进一步思考,如果对象有方法,这是不够的。当你序列化时,你失去了方法,所以只保留属性 – yitwail 2012-04-07 23:56:04

2

前几天有类似的问题,而这些答案都是正确的路径;我用它们来制定出以下几点:

从Artefacto的回答return $obj1 == $obj2并没有真正的工作,所以我写了一个简单的比较功能(基本上得到序列化对象的MD5和比较了):

function object_compare($obj1, $obj2){ 
    $md5 = function($obj){ 
    return md5(serialize($obj)); 
    }; 
    return strcmp($md5($obj1), $md5($obj2)); 
} 

那么它的突出部分调用和array_uintersect与我们的比较函数来获取交集的问题:

# $array1/$array2 are the array of objects we want to compare 
return array_uintersect($array1, $array2, 'object_compare'); 

就我而言,我有对象的未知/动态数组,所以我把它更进了一步,所以我不要”不得不申报array_uintersect($array1, $array2, ...)特别 - 只是能在(对象)数组的数组来传递:

# $multiarray_of_objects is our array of arrays 
$multiarray_of_objects[] = 'object_compare'; 
return call_user_func_array('array_uintersect', $multiarray_of_objects); 

只要得记得在参考我们的回调/对比功能数组中的最后一个字符串传递。奇迹般有效!

+0

由于在控制器类中工作,我不能这样做,但使用Artefacto格式的方法像魅力一样工作。 – Magnanimity 2014-04-02 12:46:38

+0

在类'返回array_uintersect($ array1,$ array2,'self :: object_compare');'应该工作,甚至'ClassName :: object_compare',但记住它需要是一个公共类函数。 – Atari 2017-08-18 14:59:46

0

我使用array_udiff来实现object array的array_intersect。

function diff($a, $b) { 
if($a === $b) { 
    return 0; 
} else { 
    return 1;} 
} 

$array_1 = array('a', 'b', 'c');  

$array_2 = array('c', 'd','e');  

$array = array_udiff($array_1, array_udiff($array_1, $array_2, 'diff'),'diff'); 

var_dump($array); 
return array(1) { [2]=> string(1) "c" } 

对于任何方案您都可以拥有自己的diff功能。

8

您可以结合使用和array_uintersect与spl_object_hash,看一个例子:

array_uintersect($a, $b, function($a, $b) { 
     return strcmp(spl_object_hash($a), spl_object_hash($b)); 
    }); 

其中“$ a”和“$ B”是要交一些对象的数组。

+0

很好的解决方案。对于当代读者来说:在php7中,'strcmp()'可以用'<=>'运算符代替,如下所示:'return spl_object_hash($ a)<=> spl_object_hash($ b);' – 2017-10-03 10:41:37

-1

正确的解决办法是:

array_uintersect($arr1, $arr2, function ($a1, $a2) { return $a1 != $a2; }); 

注意=中,而不是从@Artefacto答案回调函数!基于array_uintersect的文档,如果数组项相等,则回调函数必须返回0(假)。

+0

这是一种不必要的类型破解,如果第一个值小于,等于或大于第二个值,则回调函数应该返回整数(-1,0,1),就像排序函数一样。隐含的0到0的类型转换会混淆你的代码的读者。 – amik 2017-05-14 15:30:23

0

只是为了完整:在您的对象中实现__toString()方法返回一个唯一值。对于数据库实体而言,这可能与返回完全限定的类名后缀与记录的ID一样简单。但是通过做一些散列或者甚至更糟糕的事情也可能是任意复杂的。

在我看来,这是班级的责任,要序列化自己或创建一些独特的东西来比较它的对象。使用类之外的任何东西来序列化对象可能会导致奇怪的行为(包括比较不同类的对象,这绝不会导致相等)。