【问题标题】:Remove duplicates from an array based on object property?根据对象属性从数组中删除重复项?
【发布时间】:2012-05-17 08:36:24
【问题描述】:

我有一个对象数组。我想根据对象中的“名称”值删除重复项。

  [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 重复数组问题,但似乎没有一个处理对象并仅根据一个参数进行过滤。

【问题讨论】:

    标签: php object multidimensional-array duplicate-removal


    【解决方案1】:

    对于php >=7.0:

    由于array_column 自 PHP 7.0 起适用于对象数组,您可以按照@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
            )
    
    )
    

    term_id 为 15 的对象已被删除,因为它与 term_id 14 同名。

    对于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 为 15 的对象已被删除,因为它与 term_id 14 同名。

    【讨论】:

    • 这很接近,但我也需要访问“slug”和“term_id”键。我正在玩,看看我能不能弄明白。
    • 之后你就有了访问权限,它只是为了找出要删除的键。我将在几秒钟内发布一个完整的示例。
    • 谢谢。在我已经研究了几个小时的一个相当复杂的问题上效果很好。
    【解决方案2】:

    单线:

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

    请注意,array_column() 适用于 PHP 7 及更高版本中的对象数组。

    【讨论】:

    • 这应该是经过批准的解决方案。单线永远是最好的!
    • @UlisesVargasDeSousa 我已将此 PHP >=7.0 解决方案添加到已接受的答案中,同时保留
    【解决方案3】:

    我一直在寻找一个好的答案,但找不到一个,所以我自己写了一个来处理这种情况,以及你想基于多个属性进行重复数据删除的情况。

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

    【讨论】:

      【解决方案4】:

      我需要同样的东西...... 这就是我所做的(基于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;
      }
      

      【讨论】:

        【解决方案5】:

        有点离题,但密切相关:仅按实例对对象数组进行重复数据删除的最短方法:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-06-29
          • 2016-11-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-01-14
          • 2014-03-08
          • 1970-01-01
          相关资源
          最近更新 更多