12

I have an array of objects. I'd like to remove the duplicates based on the "name" value in the object.

  [0]=>
  object(stdClass)#337 (9) {
    ["term_id"]=>
    string(2) "23"
    ["name"]=>
    string(12) "Assasination"
    ["slug"]=>
    string(12) "assasination"
  }
  [1]=>
  object(stdClass)#44 (9) {
    ["term_id"]=>
    string(2) "14"
    ["name"]=>
    string(16) "Campaign Finance"
    ["slug"]=>
    string(16) "campaign-finance"
  }
  [2]=>
  object(stdClass)#298 (9) {
    ["term_id"]=>
    string(2) "15"
    ["name"]=>
    string(16) "Campaign Finance"
    ["slug"]=>
    string(49) "campaign-finance-good-government-political-reform"
  }

So in this case, how do I remove the duplicate "Campaign Finance" object from the array. So the entire [2] object?

I've gone through a bunch of the PHP duplicate array question here, but none seemed to deal with objects and filtering just off of one parameter.

5 Answers 5

18

For php >=7.0:

Since array_column works on object-arrays since PHP 7.0 you can use the following combination as suggested by @plashenkov:

$filtered = array_intersect_key($array, array_unique(array_column($array, 'someProperty')));

Full example: https://3v4l.org/IboLu#v8.0.8

class my_obj
{
        public $term_id;
        public $name;
        public $slug;

        public function __construct($i, $n, $s)
        {
                $this->term_id = $i;
                $this->name = $n;
                $this->slug = $s;
        }
}

$objA = new my_obj(23, 'Assasination', 'assasination');
$objB = new my_obj(14, 'Campaign Finance', 'campaign-finance');
$objC = new my_obj(15, 'Campaign Finance', 'campaign-finance-good-government-political-reform');

$array = array($objA, $objB, $objC);
echo 'Original array:\n';
print_r($array);

/** Answer Code begins here */
$filtered = array_intersect_key($array, array_unique(array_column($array, 'name')));
/** Answer Code ends here */

echo 'After removing duplicates\n';
print_r($filtered);

Output:

Original array:
Array
(
    [0] => my_obj Object
        (
            [term_id] => 23
            [name] => Assasination
            [slug] => assasination
        )

    [1] => my_obj Object
        (
            [term_id] => 14
            [name] => Campaign Finance
            [slug] => campaign-finance
        )

    [2] => my_obj Object
        (
            [term_id] => 15
            [name] => Campaign Finance
            [slug] => campaign-finance-good-government-political-reform
        )

)
After removing duplicates
Array
(
    [0] => my_obj Object
        (
            [term_id] => 23
            [name] => Assasination
            [slug] => assasination
        )

    [1] => my_obj Object
        (
            [term_id] => 14
            [name] => Campaign Finance
            [slug] => campaign-finance
        )

)

The object with term_id 15 was removed as it had the same name as term_id 14.

For php <7.0:

Build a new array with the existing keys and just the name as value, use array_unique (note that it preserves keys).

Then copy every key from the original array to a new array ($filtered) (or remove everything thats not in the unique'ed array from the original key-wise).

Edit: Complete example: https://3v4l.org/SCrko#v5.6.40

class my_obj
{
        public $term_id;
        public $name;
        public $slug;

        public function __construct($i, $n, $s)
        {
                $this->term_id = $i;
                $this->name = $n;
                $this->slug = $s;
        }
}

$objA = new my_obj(23, 'Assasination', 'assasination');
$objB = new my_obj(14, 'Campaign Finance', 'campaign-finance');
$objC = new my_obj(15, 'Campaign Finance', 'campaign-finance-good-government-political-reform');

$array = array($objA, $objB, $objC);

echo 'Original array:\n';
print_r($array);

/** Answer Code begins here **/

// Build temporary array for array_unique
$tmp = array();
foreach($array as $k => $v)
    $tmp[$k] = $v->name;

// Find duplicates in temporary array
$tmp = array_unique($tmp);

// Build new array with only non-duplicate items
$filtered = [];
foreach($array as $k => $v)
{
    if (array_key_exists($k, $tmp))
        $filtered[$k] = $v;
}

/** Answer Code ends here **/

echo 'After removing duplicates\n';
print_r($filtered);

Output:

Original array:
Array
(
    [0] => my_obj Object
        (
            [term_id] => 23
            [name] => Assasination
            [slug] => assasination
        )

    [1] => my_obj Object
        (
            [term_id] => 14
            [name] => Campaign Finance
            [slug] => campaign-finance
        )

    [2] => my_obj Object
        (
            [term_id] => 15
            [name] => Campaign Finance
            [slug] => campaign-finance-good-government-political-reform
        )

)
After removing duplicates
Array
(
    [0] => my_obj Object
        (
            [term_id] => 23
            [name] => Assasination
            [slug] => assasination
        )

    [1] => my_obj Object
        (
            [term_id] => 14
            [name] => Campaign Finance
            [slug] => campaign-finance
        )

)

The object with term_id 15 was removed as it had the same name as term_id 14.

Sign up to request clarification or add additional context in comments.

3 Comments

This is close, but I need access to the "slug" and "term_id" key's too. I'm playing around to see if I can figure it out.
You have that access afterward, its just for finding out which keys to delete. I'll post a complete example in a sec.
thank you. works great on a pretty complex problem i've been working on for hours.
9

One-liner:

$filtered = array_intersect_key($array, array_unique(array_column($array, 'someProperty')));

Please note that array_column() works with array of objects in PHP 7 and newer.

2 Comments

This should be the approved solution. One-liner always is the best!
@UlisesVargasDeSousa I've added this PHP >=7.0 solution to the accepted answer while keeping the <7.0 alternative. Note that PHP7 wasn't a thing in 2012 ;-)
2

I was searching for a good answer to this and couldn't find one, so I've written my own that will handle this case, and the case when you want to de-dupe based on multiple properties.

$array = DeDupeArrayOfObjectsByProps($array, ['name']);

Here's the generic function:

/**
 * Iterates over the array of objects and looks for matching property values.
 * If a match is found the later object is removed from the array, which is returned
 * @param array $objects    The objects to iterate over
 * @param array $props      Array of the properties to dedupe on.
 *   If more than one property is specified then all properties must match for it to be deduped.
 * @return array
 */
public function DeDupeArrayOfObjectsByProps($objects, $props) {
    if (empty($objects) || empty($props))
        return $objects;
    $results = array();
    foreach ($objects as $object) {
        $matched = false;
        foreach ($results as $result) {
            $matchs = 0;
            foreach ($props as $prop) {
                if ($object->$prop == $result->$prop)
                    $matchs++;
            }
            if ($matchs == count($props)) {
                $matched = true;
                break;
            }

        }
        if (!$matched)
            $results[] = $object;
    }
    return $results;
}

Here's the full usage for your case:

class my_obj {
    public $term_id;
    public $name;
    public $slug;

    public function __construct($i, $n, $s) {
        $this->term_id = $i;
        $this->name = $n;
        $this->slug = $s;
    }
}

$objA = new my_obj(23, "Assasination", "assasination");
$objB = new my_obj(14, "Campaign Finance", "campaign-finance");
$objC = new my_obj(15, "Campaign Finance", "campaign-finance-good-government-political-reform");
$array = array($objA, $objB, $objC);

$array = DeDupeArrayOfObjectsByProps($array, ['name']);
var_dump($array);

Comments

1

I needed the same thing... Here's what I did (work for both array and objects, based on this post)

function my_array_unique_by_subkey($array,$subkey){

    $temp = array();

    $unique = array_filter($array, function ($v) use (&$temp,$subkey) {

        if ( is_object($v) ) $v = (array)$v;

        if ( !array_key_exists($subkey,$v) ) return false;

        if ( in_array($v[$subkey], $temp) ) {
            return false;
        } else {
            array_push($temp, $v[$subkey]);
            return true;
        }
    });

    return $unique;
}

Comments

1

Slightly off-topic, but closely related: the shortest way to dedupe an array of objects just by their instance:

/**
 * The array must NOT contain scalars.
 *
 * @param mixed[] $objects
 * @return mixed[]
 */
public static function arrayUniqueForObjects(array $objects): array
{
    $deDuplicatedArray = [];

    foreach ($objects as $object) {
        $deDuplicatedArray[spl_object_hash($object)] = $object;
    }

    return array_values($deDuplicatedArray);
}

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.