Есть ли такой метод, как array_unique для объектов? У меня есть несколько массивов с объектами «Роль», которые я объединяю, а затем хочу удалить дубликаты :)
Ну, array_unique()сравниваем строковое значение элементов:
Примечание : два элемента считаются равными тогда и только тогда, (string) $elem1 === (string) $elem2когда, например, когда строковое представление одинаково, будет использоваться первый элемент.
Поэтому не забудьте реализовать __toString()метод в своем классе и чтобы он выводил одно и то же значение для равных ролей, например
@Jacob , потому что ни array_uniqueни __toString()сравнивать что - либо. __toString()определяет, как должен вести себя экземпляр объекта при использовании в строковом контексте, и array_uniqueвозвращает входной массив с удаленными повторяющимися значениями. Для этого он просто использует сравнение.
Гордон,
1
@ Джейкоб Релкин: Это не компаратор. Это строковое представление объекта. Я думаю, они используют это, поскольку вы можете преобразовать любой тип, объект и т. Д. В строку. Но сам строковый метод объекта используется не только этой функцией. Например, echo $objectтоже использует __toStringметод.
Феликс Клинг
3
Добавление __toString()методов ко всем вашим объектам намного более болезненно, чем просто добавление SORT_REGULARфлага в array_unique, см. Ответ Матье Наполи. Кроме того, у __toString()метода есть много других вариантов использования, которые затем используются для сравнения объектов, поэтому это может быть даже невозможно.
Flip
156
array_uniqueработает с массивом объектов, используя SORT_REGULAR:
Предупреждение : будет использоваться сравнение «==», а не строгое сравнение («===»).
Поэтому, если вы хотите удалить дубликаты внутри массива объектов, помните, что он будет сравнивать свойства каждого объекта, а не идентичность объекта (экземпляр).
Этот ответ намного лучше принятого. Однако в примере не показана разница между сравнением по значению ( ==) или identity ( ===) из-за $bam->prop = 'test2';(должно быть, 'test1'чтобы продемонстрировать разницу). См. Пример на codepad.viper-7.com/8NxWhG .
Должен быть принятый ответ. Также это намного быстрее, чем использование __toString (). См .: sandbox.onlinephpfunctions.com/code/… для получения результатов сравнения.
LucaM
1
Следите за сравнением объектов с помощью array_unique (), функция применит глубокое сравнение, которое может привести к сбою вашего сервера, если оно связано со слишком большой рекурсией - я смотрю на вас, сущности Doctrine. Лучше определите, что делает ваш объект уникальным, и индексируйте с его помощью ваши объекты. Например, если ваши объекты имеют строковый идентификатор, создайте массив с этим идентификатором в качестве ключа.
olvlvl
31
Этот ответ использует, in_array()поскольку природа сравнения объектов в PHP 5 позволяет нам это делать. Использование этого поведения сравнения объектов требует, чтобы массив содержал только объекты, но, похоже, здесь так и есть.
Работает хорошо, он может быть быстрее, чем другой (правда, не знаю), но я буду использовать ваш, потому что мне не нужно делать для него дополнительную функцию: D
Gigala
При сравнении объектов они должны иметь одинаковое количество полей и должны быть идентичными парами ключ / значение, чтобы считаться одинаковыми? что я получаю, так это .... если у меня есть 2 объекта, и у одного из них есть одно дополнительное поле, эти объекты не будут считаться «одинаковыми»
Отказ от использования строгого параметра здесь был сознательным выбором. Я хотел найти «равные» объекты, не обязательно один и тот же экземпляр объекта. Это объясняется в ссылке, упомянутой в ответе, в которой говорится: « При использовании оператора сравнения (==) объектные переменные сравниваются простым способом, а именно: два экземпляра объекта равны, если они имеют одинаковые атрибуты и значения, и являются экземплярами одного и того же класса »
салате
Работает как шарм! Большое спасибо
gronaz
17
Вот способ удалить повторяющиеся объекты в массиве:
<?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($arrayas$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);
Для меня это лучшее решение! Я использую это решение для своего поискового механизма на своем веб-сайте (слияние двух результатов запроса из базы данных). Сначала у меня есть результаты для всех поисковых запросов, и я объединяю их с результатами некоторых поисковых запросов. С этим решением я сначала получаю самые важные результаты, добавленные другими уникальными решениями.
Если у вас есть индексированный массив объектов и вы хотите удалить дубликаты, сравнивая определенное свойство в каждом объекте, можно использовать функцию, подобную приведенной remove_duplicate_models()ниже.
array_unique работает путем преобразования элементов в строку и выполнения сравнения. Если ваши объекты не будут однозначно преобразованы в строки, они не будут работать с array_unique.
Вместо этого реализуйте для своих объектов функцию сравнения с отслеживанием состояния и используйте array_filter, чтобы отбрасывать то, что функция уже видела.
Если у вас есть массив объектов и вы хотите отфильтровать эту коллекцию, чтобы удалить все дубликаты, вы можете использовать array_filter с анонимной функцией:
$myArrayOfObjects = $myCustomService->getArrayOfObjects();
// This is temporary array$tmp = [];
$arrayWithoutDuplicates = array_filter($myArrayOfObjects, function ($object) use (&$tmp) {
if (!in_array($object->getUniqueValue(), $tmp)) {
$tmp[] = $object->getUniqueValue();
returntrue;
}
returnfalse;
});
Важно: помните, что вы должны передать $tmpмассив в качестве ссылки на функцию обратного вызова фильтра, иначе она не будет работать.
Ответы:
Ну,
array_unique()
сравниваем строковое значение элементов:Поэтому не забудьте реализовать
__toString()
метод в своем классе и чтобы он выводил одно и то же значение для равных ролей, напримерclass Role { private $name; //..... public function __toString() { return $this->name; } }
Это будет рассматривать две роли как равные, если они имеют одинаковое имя.
источник
array_unique
ни__toString()
сравнивать что - либо.__toString()
определяет, как должен вести себя экземпляр объекта при использовании в строковом контексте, иarray_unique
возвращает входной массив с удаленными повторяющимися значениями. Для этого он просто использует сравнение.echo $object
тоже использует__toString
метод.__toString()
методов ко всем вашим объектам намного более болезненно, чем просто добавлениеSORT_REGULAR
флага в array_unique, см. Ответ Матье Наполи. Кроме того, у__toString()
метода есть много других вариантов использования, которые затем используются для сравнения объектов, поэтому это может быть даже невозможно.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
Предупреждение : будет использоваться сравнение «==», а не строгое сравнение («===»).
Поэтому, если вы хотите удалить дубликаты внутри массива объектов, помните, что он будет сравнивать свойства каждого объекта, а не идентичность объекта (экземпляр).
источник
==
) или identity (===
) из-за$bam->prop = 'test2';
(должно быть,'test1'
чтобы продемонстрировать разницу). См. Пример на codepad.viper-7.com/8NxWhG .Этот ответ использует,
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);
источник
in_array
следует использовать$strict
параметр! Иначе вы сравниваете объекты, используя «==» вместо «===». Подробнее здесь: fr2.php.net/manual/fr/function.in-array.phpВот способ удалить повторяющиеся объекты в массиве:
<?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 );
источник
Вы также можете использовать функцию 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; });
источник
Отсюда: 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); } ?>
источник
Если у вас есть индексированный массив объектов и вы хотите удалить дубликаты, сравнивая определенное свойство в каждом объекте, можно использовать функцию, подобную приведенной
remove_duplicate_models()
ниже.class Car { private $model; public function __construct( $model ) { $this->model = $model; } public function get_model() { return $this->model; } } $cars = [ new Car('Mustang'), new Car('F-150'), new Car('Mustang'), new Car('Taurus'), ]; function remove_duplicate_models( $cars ) { $models = array_map( function( $car ) { return $car->get_model(); }, $cars ); $unique_models = array_unique( $models ); return array_values( array_intersect_key( $cars, $unique_models ) ); } print_r( remove_duplicate_models( $cars ) );
Результат:
Array ( [0] => Car Object ( [model:Car:private] => Mustang ) [1] => Car Object ( [model:Car:private] => F-150 ) [2] => Car Object ( [model:Car:private] => Taurus ) )
источник
разумный и быстрый способ, если вам нужно отфильтровать повторяющиеся экземпляры (например, сравнение "===") из массива и:
является:
//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
источник
Это очень простое решение:
$ids = array(); foreach ($relate->posts as $key => $value) { if (!empty($ids[$value->ID])) { unset($relate->posts[$key]); } else{ $ids[$value->ID] = 1; } }
источник
array_unique работает путем преобразования элементов в строку и выполнения сравнения. Если ваши объекты не будут однозначно преобразованы в строки, они не будут работать с array_unique.
Вместо этого реализуйте для своих объектов функцию сравнения с отслеживанием состояния и используйте array_filter, чтобы отбрасывать то, что функция уже видела.
источник
array_unique
используется с SORT_REGULAR, см. мой ответ ниже.Это мой способ сравнения объектов с простыми свойствами и в то же время получения уникальной коллекции:
class Role { private $name; public function __construct($name) { $this->name = $name; } public function getName() { return $this->name; } } $roles = [ new Role('foo'), new Role('bar'), new Role('foo'), new Role('bar'), new Role('foo'), new Role('bar'), ]; $roles = array_map(function (Role $role) { return ['key' => $role->getName(), 'val' => $role]; }, $roles); $roles = array_column($roles, 'val', 'key'); var_dump($roles);
Выведет:
array (size=2) 'foo' => object(Role)[1165] private 'name' => string 'foo' (length=3) 'bar' => object(Role)[1166] private 'name' => string 'bar' (length=3)
источник
Если у вас есть массив объектов и вы хотите отфильтровать эту коллекцию, чтобы удалить все дубликаты, вы можете использовать array_filter с анонимной функцией:
$myArrayOfObjects = $myCustomService->getArrayOfObjects(); // This is temporary array $tmp = []; $arrayWithoutDuplicates = array_filter($myArrayOfObjects, function ($object) use (&$tmp) { if (!in_array($object->getUniqueValue(), $tmp)) { $tmp[] = $object->getUniqueValue(); return true; } return false; });
Важно: помните, что вы должны передать
$tmp
массив в качестве ссылки на функцию обратного вызова фильтра, иначе она не будет работать.источник