【问题标题】:array intersect for object array php对象数组php的数组相交
【发布时间】:2011-02-19 13:08:24
【问题描述】:

我想知道如何对对象数组进行array_intersect。

【问题讨论】:

  • 你所说的“对象数组”是什么意思——你是指一个对象数组吗?
  • 是的,就是对象数组。

标签: php arrays object


【解决方案1】:

不错的 toString 函数已经实现并被称为 serialize ;) 所以

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

将完成这项工作,上面提到的示例不起作用,因为 array_intersect 仅适用于有人提到的字符串

【讨论】:

  • 进一步思考,如果对象有方法,这还不够。当你序列化时,你会丢失方法,所以只保留属性
【解决方案2】:

仅出于完整性考虑:在您的对象中实现 __toString() 方法,返回一个唯一值。对于数据库实体,这可能就像返回带有记录 ID 后缀的完全限定类名一样简单。但它也可以通过做一些散列甚至更糟的事情来任意复杂。

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

【讨论】:

    【解决方案3】:

    正确的解决方案是:

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

    注意回调函数中的 != 与@Artefacto 的答案相反。根据array_uintersect的文档,如果数组项相等,回调函数必须返回0(false)。

    【讨论】:

    • 这是一个不必要的类型 hack,如果第一个值小于、等于或大于第二个值,回调函数应该返回整数 (-1, 0, 1),就像排序函数一样。将 false 隐式类型转换为 0 会使代码的读者感到困惑。
    【解决方案4】:

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

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

    其中 '$a' 和 '$b' 是您想要相交的一些对象的数组。

    【讨论】:

    • 不错的解决方案。对于当代读者:在 php7 中,strcmp() 可以替换为 <=> 运算符,如下所示:return spl_object_hash($a) <=> spl_object_hash($b);
    • 正在寻找那个。很好的解决方案。你也可以使用 array_uintersect($a, $b, array($this, 'your_class_method')),以防你想在你的类中引用一个方法!
    【解决方案5】:

    我使用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" }
    

    对于任何方案,您都可以拥有自己的差异函数。

    【讨论】:

      【解决方案6】:

      几天前遇到了类似的问题,虽然这些答案都在正确的道路上;我用它们来解决以下问题:

      来自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);
      

      只需记住将回调/比较函数的引用作为数组中的最后一个字符串传递。像魅力一样工作!

      【讨论】:

      • 由于在控制器类中工作,我不能完全这样做,但使用 Artefacto 格式的方法就像一个魅力。
      • 在一个类中return array_uintersect($array1, $array2, 'self::object_compare'); 应该可以工作,甚至是ClassName::object_compare,但是记住它需要是一个公共类函数。
      【解决方案7】:

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

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

      【讨论】:

      • 您必须更具体。什么不起作用?是否有任何错误信息?什么错误信息?输出不是预期的?期待什么?你得到了什么?
      • 这不起作用,因为 array_unintersect 需要比较函数返回 1、-1 或 0。完整说明和示例请参见此处php.net/manual/en/function.array-uintersect.php#72841
      【解决方案8】:

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

      那么在这个上下文中存在的含义(确切地说是这个函数),我在 php.net 上找到了我的答案:

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

      如果你的对象没有实现到字符串的唯一转换,你就不能在对象数组上使用它。

      【讨论】:

      • 那是不准确的。至少有三种方法可以将对象转换为字符串。它们可能是一个 PHP 类并实现了 __toString,它们可能有一个接受 IS_STRING 的强制转换处理程序,它们可能有一个返回可转换为字符串的 zval 的 get 处理程序。
      • +1 @Artefacto,提交一个使用任意对象和 array_intersect() 的示例的答案。
      猜你喜欢
      • 2012-01-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多