2
\$\begingroup\$

I'm learning to code PHP and gave myself a challenge: Filter array data by matching a specific element value for duplication. I went through it logically on paper then wrote code and it worked on the first try :) But I bet it is the most inefficient way, so to learn I would like to compare it against what others would do. Below is my code. The array is just a few elements with keys like name and id. My result is a list of only items with unique ids from an array with many duplicate ids but different names.

Also, part of the challenge was testing XML, JSON, and Arrays so I made the original data XML and used SimpleXML but made a copy of that data as a PHP array and worked with that to do filtering (XPath challenge next).

Thanks for looking and any suggested improvements that I can learn from.

//$items is a SimpleXML array of items with name and id elements with many duplicate ids but different names.

//first iteration of id collection
$ids = array();
$countedIds = array();
//convert simplexml array $items to normal array (copy)
$itemsArray = json_decode(json_encode($items), TRUE);           
foreach ($itemsArray as $idItem) 
{
    //collection all ids
    $ids[] = $idItem['id'];     
}
//count number of each id and store in separate array
$countedIds = array_count_values($ids);
#print_r($countedIds);

//start cleaning out duplicates
foreach($itemsArray as $key => &$item)
{
    //clear any whitespace (thanks internets)
    #$thisid = trim($item->id); //if using simplexml
    $thisid = trim($item['id']);
    //check if this id is duplicated (multiple copies) in array
    if($countedIds[$thisid] >1)
    {
        echo $thisid . "item has duplicates (" . $countedIds[$thisid] . ")<br />";
        //add found dupes to separate array
        $dupes[] = $thisid;
        //remove this item from $itemsArray and original $items simplexml array
        unset($itemsArray[$key]);
        unset($items[$key]);
        echo "removed element index " . $key . $item . "<br /><hr>";                    
        //remove this id from $ids array
        unset($ids[$key]);
        //clear out the counted ids
        unset($countedIds);
        //make a fresh array for counting ids
        $countedIds = array();
        //get updated id count
        $countedIds = array_count_values($ids);

        //test simplexml unset?
        #unset($sxe->$this->channel->item);
    }
}       
//review results
print_r($countedIds);
print_r($ids);
print_r($dupes);
print_r($itemsArray);
print_r($items);
\$\endgroup\$
1
\$\begingroup\$

If the sole purpose was to have a resultant array of objects that did not have a duplicated id then I would be tempted with the below:

// Indexes keyed by item id
$indexes = array();

// Cast to array of objects
$items = current((array)$items);

foreach ($items as $index => $item) {
    $id = ((array)$item)['id'];

    if (isset($indexes[$id])) {
        // Unset this item
        unset($items[$index]);
        // Unset the original instance
        unset($items[$indexes[$id]]);
    } else {
        $indexes[$id] = $index;
    }
}

// List names of items that doesn't have an id that is duplicated
foreach ($items as $item) {
    // Still have original SimpleXml object to work with
    echo $item->name . "\n";
}
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.