基于对象属性从数组中删除重复项?

11
我有一个对象数组。我想根据对象中"名称"的值来删除重复的项目。
我有一个对象数组。我想根据对象中"名称"的值来删除重复的项目。
  [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"
  }
所以在这种情况下,我该如何从数组中删除重复的“Campaign Finance”对象。整个[2]对象?
我已经查看了许多PHP重复数组问题,但没有一个似乎处理对象并仅根据一个参数进行过滤。
5个回答

17

对于php >=7.0

自从 PHP 7.0 以来,array_column 可以用于对象数组,您可以使用如下组合,如 @plashenkov 所建议的:

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

完整示例: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);

输出:

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
        )

)

由于与术语ID 14具有相同名称,已删除术语ID 15的对象。

对于php <7.0

使用现有键构建一个新数组,并将仅名称用作值,使用array_unique(请注意,它保留键)。 然后将原始数组中的每个键复制到新数组($filtered)中(或者根据唯一化的数组从原始键中删除所有内容)。

编辑:完整示例: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);

输出:

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
        )

)

由于与 term_id 14 相同,具有 term_id 15 的对象已被删除。


这很接近了,但我还需要访问“slug”和“term_id”键。我正在尝试一下看能否弄清楚它。 - Drew Baker
你之后会拥有那个访问权限,它仅用于找出要删除哪些键。我会在一秒钟内发布完整的示例。 - ccKep
非常感谢。这个代码在我花费几个小时处理的一个相当复杂的问题上运行得非常好。 - byron

9

一句话简述:

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

请注意,在PHP 7及更高版本中,array_column()函数可以与对象数组一起使用。

这应该是批准的解决方案。一行代码总是最好的! - Ulises Vargas De Sousa
@UlisesVargasDeSousa 我已经将这个 PHP >=7.0 的解决方案添加到了被接受的答案中,同时保留了 <7.0 的替代方案。请注意,PHP7 在2012年还不存在;-) - ccKep

2

我在寻找一个好的答案,但是没有找到,所以我写了自己的答案来处理这种情况,还有当你想要根据多个属性去重时的情况。

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

这是通用函数:

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

以下是适用于您情况的完整用法:

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

1

我需要同样的东西......这是我做的(适用于数组和对象,基于这篇文章

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

1

有些离题,但与编程紧密相关:仅通过对象实例去重数组的最短方法:

/**
 * 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);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接