array_unique для объектов?

Есть ли какой-либо метод, например array_unique для объектов? У меня есть куча массивов с объектами «Роль», которые я объединяю, а затем я хочу вынуть дубликаты 🙂

Ну, array_unique() сравнивает строковое значение элементов:

Примечание . Два элемента считаются равными тогда и только тогда (string) $elem1 === (string) $elem2 т. (string) $elem1 === (string) $elem2 Когда строковое представление будет одинаковым, будет использоваться первый элемент.

Поэтому обязательно реализуйте __toString() в своем классе и выведите одно и то же значение для равных ролей, например

 class Role { private $name; //..... public function __toString() { return $this->name; } } 

Это будет рассматривать две роли как равные, если они имеют одно и то же имя.

array_unique работает с массивом объектов, используя SORT_REGULAR :

 class MyClass { public $prop; } $foo = new MyClass(); $foo->prop = 'test1'; $bar = $foo; $bam = new MyClass(); $bam->prop = 'test2'; $test = array($foo, $bar, $bam); print_r(array_unique($test, SORT_REGULAR)); 

Будет печать:

 Array ( [0] => MyClass Object ( [prop] => test1 ) [2] => MyClass Object ( [prop] => test2 ) ) 

Смотрите здесь в действии: http://3v4l.org/VvonH#v529

Предупреждение : оно будет использовать сравнение «==», а не строгое сравнение («===»).

Поэтому, если вы хотите удалить дубликаты внутри массива объектов, остерегайтесь того, что он будет сравнивать свойства каждого объекта, а не сравнивать идентификатор объекта (экземпляр).

Я знаю, что есть уже принятый ответ, но вот альтернатива.

Вопреки предыдущему ответу, он использует in_array() поскольку природа сравнения объектов в PHP 5 позволяет нам это сделать. Использование этого поведения сравнения объектов требует, чтобы массив содержал только объекты, но это, как представляется, имеет место здесь.

 $merged = array_merge($arr, $arr2); $final = array(); foreach ($merged as $current) { if ( ! in_array($current, $final)) { $final[] = $current; } } var_dump($final); 

Ниже приведен способ удаления дублированных объектов в массив:

 <?php // Here is the array that you want to clean of duplicate elements. $array = getLotsOfObjects(); // Create a temporary array that will not contain any duplicate elements $new = array(); // Loop through all elements. serialize() is a string that will contain all properties // of the object and thus two objects with the same contents will have the same // serialized string. When a new element is added to the $new array that has the same // serialized value as the current one, then the old value will be overridden. foreach($array as $value) { $new[serialize($value)] = $value; } // Now $array contains all objects just once with their serialized version as string. // We don't care about the serialized version and just extract the values. $array = array_values($new); 

Вы также можете сериализовать сначала:

 $unique = array_map( 'unserialize', array_unique( array_map( 'serialize', $array ) ) ); 

Начиная с PHP 5.2.9 вы можете просто использовать sort_flag SORT_REGULAR :

 $unique = array_unique( $array, SORT_REGULAR ); 

Отсюда: http://php.net/manual/en/function.array-unique.php#75307

Это тоже будет работать с объектами и массивами.

 <?php function my_array_unique($array, $keep_key_assoc = false) { $duplicate_keys = array(); $tmp = array(); foreach ($array as $key=>$val) { // convert objects to arrays, in_array() does not support objects if (is_object($val)) $val = (array)$val; if (!in_array($val, $tmp)) $tmp[] = $val; else $duplicate_keys[] = $key; } foreach ($duplicate_keys as $key) unset($array[$key]); return $keep_key_assoc ? $array : array_values($array); } ?> с <?php function my_array_unique($array, $keep_key_assoc = false) { $duplicate_keys = array(); $tmp = array(); foreach ($array as $key=>$val) { // convert objects to arrays, in_array() does not support objects if (is_object($val)) $val = (array)$val; if (!in_array($val, $tmp)) $tmp[] = $val; else $duplicate_keys[] = $key; } foreach ($duplicate_keys as $key) unset($array[$key]); return $keep_key_assoc ? $array : array_values($array); } ?> 

Вы также можете использовать функцию array_filter, если вы хотите фильтровать объекты на основе определенного атрибута:

 //filter duplicate objects $collection = array_filter($collection, function($obj) { static $idList = array(); if(in_array($obj->getId(),$idList)) { return false; } $idList []= $obj->getId(); return true; }); 

разумным и быстрым способом, если вам нужно фильтровать дублированные экземпляры (например, сравнение «===») из массива и:

  • вы уверены, что массив содержит только объекты
  • вам не нужны ключи, сохраненные

является:

 //sample data $o1 = new stdClass; $o2 = new stdClass; $arr = [$o1,$o1,$o2]; //algorithm $unique = []; foreach($arr as $o){ $unique[spl_object_hash($o)]=$o; } $unique = array_values($unique);//optional - use if you want integer keys on output 

array_unique работает, отбрасывая элементы в строку и проводя сравнение. Если ваши объекты не будут однозначно применены к строкам, они не будут работать с array_unique.

Вместо этого реализуйте функцию сравнения состояний для ваших объектов и используйте array_filter, чтобы выкинуть то, что функция уже увидела.