Array_Unique For Objects

array_unique for objects?

Well, array_unique() compares the string value of the elements:

Note: Two elements are considered equal if and only if (string) $elem1 === (string) $elem2 i.e. when the string representation is the same, the first element will be used.

So make sure to implement the __toString() method in your class and that it outputs the same value for equal roles, e.g.

class Role {
private $name;

//.....

public function __toString() {
return $this->name;
}

}

This would consider two roles as equal if they have the same name.

How can use array_unique function in stdClass Object Array PHP

You can remove duplicate objects like this:

$array = array_map('json_encode', $array);
$array = array_unique($array);
$array = array_map('json_decode', $array);

array_map is a function in php where you can apply a function (in this case json_encode) to each value in the array. So every stdClass Object in your array is encoded in a JSON string. array_unique then filters every value in the array and removes any duplicates. In your case the objects where probably not 100% duplicated but contained minor differences and you probably should use the next method. Then we apply the same trick but with json_decode to revert the JSON string to an object. You can also use serialize and unserialize for encoding and decoding the object from/to a string.


In case you to remove the objects with, for example, the same product_id you can do it this way.

$_tmp = array();
foreach($array as $key => $value) {
if(!array_key_exists($value->product_id),$_tmp) {
$_tmp [$value->product_id] = $value;
}
}
$array = array_values($_tmp);

First we create an empty array, in this case $_tmp (derived from temporary, because we don't need it afterwards). Then we loop thru the array. With array_key_exists we check if a key ($value->product_id) is not set in the array ($_tmp). Then we set assign the object to the key with the product_id. So if there is another object with the same product_id, it won't be added to the $_tmp array. The last line is assigning the object to the $array with array_values so the keys are reset.

Why array_unique does not detect duplicate objects?

For your issue at hand, I am really suspecting this is coming from the way
array_unique is removing elements out of the array, when using the SORT_REGULAR flag, by:

  1. sorting it
  2. removing adjacent items if they are equal

And because you do have a Proxy object in the middle of your User collection, this might cause you the issue you are currently facing.

This seems to be backed up by the warning of the sort page of PHP documentation, as pointed out be Marvin's comment.

Warning Be careful when sorting arrays with mixed types values because sort() can produce unexpected results, if sort_flags is SORT_REGULAR.

Source: https://www.php.net/manual/en/function.sort.php#refsect1-function.sort-notes


Now for a possible solution, this might get you something more Symfony flavoured.

It uses the ArrayCollection filter and contains methods in order to filter the second collection and only add the elements not present already in the first collection.

And to be fully complete, this solution is also making use of the use language construct in order to pass the second ArrayCollection to the closure function needed by filter.

This will result in a new ArrayCollection containing no duplicated user.

public static function merge(Collection $a, Collection $b, bool $unique = false): Collection {
if($unique){
return new ArrayCollection(
array_merge(
$a->toArray(),
$b->filter(function($item) use ($a){
return !$a->contains($item);
})->toArray()
)
);
}

return new ArrayCollection(array_merge($a->toArray(), $b->toArray()));
}

PHP array_unique is converted to object

The function array_unique() filters out equal values so the reason why #3 of the index is missing is because its equal to #0.

You can re-index the array with array_values():

var_dump(array_values(array_unique($errors, SORT_REGULAR)));

JavaScript perceives PHP's associative array's as an object because it only understands numeric keyed arrays.

You should be using json to communicate between both languages:

echo json_encode($errors);

As this would cause in javascript the outer the value to be turned into an array and turn each item into an object.

var arr = JSON.parse(outputofjson_encode);

console.log(arr[0].id);

Array Unique for Array of Objects with exclude option for certain keys in Object

See also array_unique for objects?

In case you work with non-stdClass object you could implement __toString to use array_unique to filter.

To filter on unique stdClass, using only a few of the attributes you could try something like:

From PHP 7 onwards you could use array_column to get a value from a stdClass, so if you use PHP7:

array_unique(array_column($array,'payrate'));

Before PHP 7 you could try:

array_unique(array_map(function($item) {return $item->payrate;},$array);

In case there are more attributes to compare there are different ways. array_reduce is just one of them.

The outcome of this one will not have any duplicates. So if all attributes match, the item will be filtered.

$attributes = ['payrate','date']
$filtered = array_reduce($array,function($carry,$item) use ($attributes) {
if(count(array_filter($attributes,function ($attribute) use ($carry, $item) {
return !in_array($item->$attribute,array_map(function($carriedItem) use ($attribute) {
return $carriedItem->$attribute;
},$carry));
}))) {
$carry[] = $item;
}
return $carry;
},[]);

see http://sandbox.onlinephpfunctions.com/code/5f8171d76362ada7e165afeaadbecffc6cdd497a

The result of array_unique

Function array_unique() will compare strings, so objects will be casted to strings. Solution to that would be to use __toString() magic method to return full date identifier:

class simpleClass
{
public $dt;

function __construct(DateTime $dt) {
$this->dt = $dt;
}

public function __toString() {
return $this->dt->format('r');
}

}

$dateObj1 = new simpleClass(new DateTime);
$dateObj2 = new simpleClass(new DateTime);
$dateObj3 = new simpleClass(new DateTime('today'));
$arr = [$dateObj1, $dateObj2, $dateObj3];

print_r(array_unique($arr));

Demo.

Array after array_unique function is returned as an object in JSON response

array_unique removes values from the array that are duplicates, but the array keys are preserved.

So an array like this:

array(1,2,2,3)

will get filtered to be this

array(1,2,3)

but the value "3" will keep his key of "3", so the resulting array really is

array(0 => 1, 1 => 2, 3 => 3)

And json_encode is not able to encode these values into a JSON array because the keys are not starting from zero without holes. The only generic way to be able to restore that array is to use a JSON object for it.

If you want to always emit a JSON array, you have to renumber the array keys. One way would be to merge the array with an empty one:

$nonunique = array(1,2,2,3);
$unique = array_unique($nonunique);
$renumbered = array_merge($unique, array());

json_encode($renumbered);

Another way to accomplish that would be letting array_values create a new consecutively-indexed array for you:

$nonunique = array(1,2,2,3);
$renumbered = array_values(array_unique($nonunique));

json_encode($renumbered);

How to get a list of unique properties from object

You can use array_unique() in php.

$categories = array();
foreach (getSourceCodes() as $source) {
array_push($categories, $source->getCategory());
}
$categories = array_unique($categories);

If categories is multidimensional, then use this method to serialise it, then get unique array and then change it back to array.

$categories = array_map("unserialize", array_unique(array_map("serialize", $categories)));

PHP Easier way to get unique in array of objects

If the JSON string of the objects is used as a key, this can also be implemented with a simple foreach loop.

$arr = [
(object)['Name' => 'Kory Kelly', 'PhoneNumber' => '(555) 555-5555'],
(object)['Name' => 'Kory Kelly', 'PhoneNumber' => '(555) 555-5555'],
(object)['Name' => 'Kory Kelly', 'PhoneNumber' => '(555) 555-5555X'], //different
];

foreach($arr as $key => $object){
$arr[json_encode($object)] = $object;
unset($arr[$key]);
}
$arr = array_values($arr);
var_dump($arr);

Try it yourself at 3v4l.org.

Compared to array_unique($arr, SORT_REGULAR ), this approach only becomes interesting if only certain keys are to be taken into account in the object comparison.



Related Topics



Leave a reply



Submit