массив уникальный для объектов?



есть ли такой метод, как array_unique для объектов? У меня есть куча массивов с "ролевыми" объектами, которые я объединяю, а затем я хочу вынуть дубликаты:)

644   10  

10 ответов:

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

Примечание: два элемента считаются равными тогда и только тогда, когда (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);
}
?>

вы также можете использовать функцию 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

Это мой способ сравнения объектов с простыми свойствами, и в то же время, получая уникальную коллекцию:

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_unique работает путем приведения элементов к строке и выполнения сравнения. Если ваши объекты не будут однозначно приведены к строкам, то они не будут работать с array_unique.

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

Comments

    Ничего не найдено.