1

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.

7
  • What have you tried? See about Stack Overflow. Commented Jun 10, 2014 at 0:48
  • I have tried manually going though array. Was wondering if there is s simpler solution. @JohnConde And, honestly, im on my 12th working hour question might be out of bounds haha Commented Jun 10, 2014 at 0:51
  • By "manually" i mean take each object in array and compare all its properties against properties in all other objects. But array might be huge. So im not sure.. at this point.. @JohnConde Commented Jun 10, 2014 at 0:58
  • I'm just curious, what happens to the "RECID" key in these duplicates above? will the second array contain just the "RECID" key, while the first remains the same? Commented Jun 10, 2014 at 1:15
  • @Charles oh sorry RECID doest exist. Just edited my question. Commented Jun 10, 2014 at 1:37

2 Answers 2

1

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);
Sign up to request clarification or add additional context in comments.

3 Comments

Cool! Thanks and bout your side note: i know! its weird but thats what i did the first time but it doesnt work! try it: $blah = ((string)'sd') !== ((string)'sd'); i think something is off because of the (string) conversion
@rinchik There is nothing wrong with $blah = ((string)'sd') !== ((string)'sd');. From documentaion: ($a !== $b) returns TRUE if $a is not equal to $b, or they are not of the same type. In your case !== returns FALSE because 'sd' is equal to 'sd' =)
I understand that. Did you actually try in an action?
0

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;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.