rinchik
rinchik

Reputation: 2670

PHP: compare objects inside of an array

How can I compare objects inside of an array?

I have a dynamically populated array of simpleXML objects (length is unknown)

Is there a fast way to compare all those objects inside the array and exclude duplicates?

And its getting a bit harder because ID field is different in every simpleXML object so I need to omit it in comparison.

For example simple short version:

Array
(
    [0] => SimpleXMLElement Object
        (
            [ID] => 556
            [FIRST] => JOHN
            [MID] => SimpleXMLElement Object
                (
                )

            [LAST] => SMITH


        )

    [1] => SimpleXMLElement Object
        (
            [ID] => 557
            [FIRST] => JOHN
            [MID] => SimpleXMLElement Object
                (
                )

            [LAST] => SMITH
        )

)

These are 2 duplicates. I need to confirm it and remove one.

This is what i have so far:

    $noDups = array();
    foreach($arr as $key=>$value)
    {
                    if (0 == $key) {
                         $noDups[] = $value;
                         continue;
                    }
        foreach($arr as $_key=>$_value)
        {

            $first = ( ((string)$value->FIRST) !== ((string)$_value->FIRST) )?true:false;
            $mid = ( ((string)$value->MID) !== ((string)$_value->MID) )?true:false;
            $last = ( ((string)$value->LAST) !== ((string)$_value->LAST) )?true:false;

            if ($first && $mid && $last)
            {
                array_push($noDups, $value);
            }
        }
    }

But i don't find this code sexy if you know what i mean.

Upvotes: 1

Views: 893

Answers (2)

Samel Vhatargh
Samel Vhatargh

Reputation: 235

The most efficient way to delete duplicates from an array is array_unique function.

As stated in documentation, this function considers that two elements are equal if and only if their string representations are equal ( (string) $elem1 === (string) $elem2 ).

The string represantion of objects can be handled by __toString magic method.

SimpleXMLElement already has __toString implementation, so, in order to exclude ID from comparison, you need to override this method:

class ComparableXMLElement extends SimpleXMLElement
{
    public function __toString()
    {
        //In order to exclude ID from comparison we need to return an unique string based only on specific attributes
        return md5("F".$this->FIRST."_M".$this->MID."_L".$this->LAST);
    }
}

Then you need populate your array with ComparableXMLElement objects instead of SimpleXMLElement and simple

$noDups = array_unique($arr);

will do the trick.


As a side note:

Since all comparison operators (e.g. !== ) already returns a boolean value, the use of ternary operator ( ? : ) is not necessary. So instead of

$first = ( ((string)$value->FIRST) !== ((string)$_value->FIRST) )?true:false;

you should write

$first = ((string)$value->FIRST) !== ((string)$_value->FIRST);

Upvotes: 1

Fabricator
Fabricator

Reputation: 12782

You can iterate over the array and build an associative array with key = what matters

$uniq = array();
foreach($arr as $obj) {
  $uniq[$obj['FIRST'] . '::' . $obj['MID'] . '::' . $obj['LAST']] = $obj;
}

Upvotes: 0

Related Questions