【问题标题】:How to remove duplicate values from a multi-dimensional array in PHP如何从 PHP 中的多维数组中删除重复值
【发布时间】:2018-09-17 06:22:55
【问题描述】:

如何在 PHP 中删除多维数组中的重复值?

示例数组:

Array
(
    [0] => Array
    (
        [0] => abc
        [1] => def
    )

    [1] => Array
    (
        [0] => ghi
        [1] => jkl
    )

    [2] => Array
    (
        [0] => mno
        [1] => pql
    )

    [3] => Array
    (
        [0] => abc
        [1] => def
    )

    [4] => Array
    (
        [0] => ghi
        [1] => jkl
    )

    [5] => Array
    (
        [0] => mno
        [1] => pql
    )

)

【问题讨论】:

    标签: php arrays duplicate-data


    【解决方案1】:

    这是另一种方式。不保存中间变量。

    我们使用它对来自各种重叠查询的结果进行重复数据删除。

    $input = array_map("unserialize", array_unique(array_map("serialize", $input)));
    

    【讨论】:

    • 由于反序列化,数组越大越复杂,速度越慢。我使用 array_intersect_key 是有原因的(比这个答案早半年)。
    • @OIS 刚刚对其进行了很好的测试,有一个错字,但它有效.. 谢谢老兄!: $no_duplicates = array_intersect_key( $array , array_unique( array_map('serialize' , $array ) ) );
    • 如果你希望索引连续,使用 array_values 即 $input = array_values(array_map("unserialize", array_unique(array_map("serialize", $input))));
    • 现在你可能会选择 json_encode 和 json_decode 而不是 PHP 序列化。应该对提供的值有好处并且您不会遇到序列化/反序列化附带的 PHP 序列化细节,而且很可能是不需要的。
    • 请注意serialize(array('a' => '1', 'b' => '1'))serialize(array('b' => '1', 'a' => '1')) 不同。对于用作sets(hash)maps 的数组,此选项将失败。
    【解决方案2】:

    从 5.2.9 开始,如果您像这样使用 SORT_REGULAR 标志,则可以使用 array_unique()

    array_unique($array, SORT_REGULAR);
    

    这使得函数比较元素是否相等,就好像使用了$a == $b,这非常适合您的情况。

    输出

    Array
    (
        [0] => Array
            (
                [0] => abc
                [1] => def
            )
    
        [1] => Array
            (
                [0] => ghi
                [1] => jkl
            )
    
        [2] => Array
            (
                [0] => mno
                [1] => pql
            )
    
    )
    

    但请记住,the documentation 声明:

    array_unique() 不适用于多维数组。

    【讨论】:

    • 我想这是比公认的解决方案更快速、更清晰的解决方案!让我们投票给这个! :) 嗯on php site 我们可以看到它并不像我想的那么快......
    • 奇怪的是,使用 SORT_REGULAR 标志对我不起作用,以删除重复的数组。
    • @Stefan 你是对的;它似乎没有给出正确的结果,但它可能是一个错误,因为它works with PHP 7 =/
    • 这似乎也适用于我的情况,但是还有其他人被 array_unique() 文档中的这个注释所困扰吗? php.net/manual/en/…
    • @Jack 你说得对,这是 PHP 5.6.23 中的一个错误:eval.in/645675,但自 PHP 7.0.8 起已修复:eval.in/645676
    【解决方案3】:

    我遇到了类似的问题,但我找到了一个 100% 可行的解决方案。

    <?php
        function super_unique($array,$key)
        {
           $temp_array = [];
           foreach ($array as &$v) {
               if (!isset($temp_array[$v[$key]]))
               $temp_array[$v[$key]] =& $v;
           }
           $array = array_values($temp_array);
           return $array;
    
        }
    
    
    $arr="";
    $arr[0]['id']=0;
    $arr[0]['titel']="ABC";
    $arr[1]['id']=1;
    $arr[1]['titel']="DEF";
    $arr[2]['id']=2;
    $arr[2]['titel']="ABC";
    $arr[3]['id']=3;
    $arr[3]['titel']="XYZ";
    
    echo "<pre>";
    print_r($arr);
    echo "unique*********************<br/>";
    print_r(super_unique($arr,'titel'));
    
    ?>
    

    【讨论】:

    【解决方案4】:

    另一种方式。也会保留密钥。

    function array_unique_multidimensional($input)
    {
        $serialized = array_map('serialize', $input);
        $unique = array_unique($serialized);
        return array_intersect_key($input, $unique);
    }
    

    【讨论】:

    • 对于大型数组,这种方法通常比公认的答案快至少 50%。
    【解决方案5】:
    Array
    (
        [0] => Array
            (
                [id] => 1
                [name] => john
            )
    
        [1] => Array
            (
                [id] => 2
                [name] => smith
            )
    
        [2] => Array
            (
                [id] => 3
                [name] => john
            )
    
        [3] => Array
            (
                [id] => 4
                [name] => robert
            )
    
    )
    
    $temp = array_unique(array_column($array, 'name'));
    $unique_arr = array_intersect_key($array, $temp);
    

    这将从数组中删除重复的名称。按键唯一

    【讨论】:

    • 确保$array 的密钥从“0”开始。如果$array 是先前数组操作的结果,则$array 的键可能从另一个数字开始。使用array_values 将密钥重置为“0”
    【解决方案6】:

    如果“删除重复项”的意思是“删除重复项,但保留一个”,解决方案可能是先在“标识符列”上应用array_unique(...),然后在原始数组中删除所有具有已从列数组中删除:

    $array = [
        [
            'id' => '123',
            'foo' => 'aaa',
            'bar' => 'bbb'
        ],
        [
            'id' => '123',
            'foo' => 'ccc',
            'bar' => 'ddd'
        ],
        [
            'id' => '567',
            'foo' => 'eee',
            'bar' => 'fff'
        ]
    ];
    
    $ids = array_column($array, 'id');
    $ids = array_unique($ids);
    $array = array_filter($array, function ($key, $value) use ($ids) {
        return in_array($value, array_keys($ids));
    }, ARRAY_FILTER_USE_BOTH);
    

    结果是:

    Array
    (
        [0] => Array
            (
                [id] => 123
                [foo] => aaa
                [bar] => bbb
            )
    
        [2] => Array
            (
                [id] => 567
                [foo] => eee
                [bar] => fff
            )
    
    )
    

    【讨论】:

      【解决方案7】:

      array_unique() 文档中的用户 cmets 对此有很多解决方案。这是其中之一:

      在 rbnsn dot com 上的 kenrbnsn
      2005 年 9 月 27 日 12:09

      另一个 Array_Unique 用于多维数组。我只在二维数组上对此进行了测试,但它可能会被推广到更多,或者使用递归。

      此函数使用 serialize、array_unique 和 unserialize 函数来完成这项工作。

      
      function multi_unique($array) {
          foreach ($array as $k=>$na)
              $new[$k] = serialize($na);
          $uniq = array_unique($new);
          foreach($uniq as $k=>$ser)
              $new1[$k] = unserialize($ser);
          return ($new1);
      }

      这是来自http://ca3.php.net/manual/en/function.array-unique.php#57202

      【讨论】:

        【解决方案8】:

        我已经尝试这样做来删除重复项。

        $array = array_map("unserialize", array_unique(array_map("serialize", $array)));
        

        【讨论】:

          【解决方案9】:

          如果您需要消除特定键上的重复项,例如 mysqli id,这里有一个简单的功能

          function search_array_compact($data,$key){
              $compact = [];
              foreach($data as $row){
                  if(!in_array($row[$key],$compact)){
                      $compact[] = $row;
                  }
              }
              return $compact;
          }
          

          奖励积分 您可以传递一个键数组并添加一个外部 foreach,但每个附加键会慢 2 倍。

          【讨论】:

            【解决方案10】:

            唯一一个多维数组的一个非常简单和合乎逻辑的方法如下,

            如果你有这样的数组:

            Array
            (
                [Key1] => Array
                    (
                        [0] => Value1
                        [1] => Value2
                        [2] => Value1
                        [3] => Value3
                        [4] => Value1
                    )
                [Key2] => Array
                    (
                        [0] => Value1
                        [1] => Value2
                        [2] => Value1
                        [3] => Value3
                        [4] => Value4
                    )
            )
            

            使用foreach 解决这个问题:

            foreach($array as $k=>$v){
                $unique=array_unique($v);
                $array[$k]=$unique;
            }
            

            它会给你以下结果:

            Array
            (
                [Key1] => Array
                    (
                        [0] => Value1
                        [1] => Value2
                        [3] => Value3
                    )
                [Key2] => Array
                    (
                        [0] => Value1
                        [1] => Value2
                        [3] => Value3
                        [4] => Value4
                    )
            )
            

            如果你想重新排列键的顺序,

            foreach($array as $k=>$v){
                $unique= array_values(array_unique($v));
                $array[$k]=$unique;
            }
            

            此操作将为您提供如下排列的键值:

            Array
            (
                [Key1] => Array
                    (
                        [0] => Value1
                        [1] => Value2
                        [2] => Value3
                    )
                [Key2] => Array
                    (
                        [0] => Value1
                        [1] => Value2
                        [2] => Value3
                        [3] => Value4
                    )
            )
            

            我希望这会清除一切。

            【讨论】:

              【解决方案11】:

              如果你有这样的数组:

              (users是数组的名字)

              Array=>
               [0] => (array)
                 'user' => 'john'
                 'age' => '23'
               [1] => (array)
                'user' => 'jane'
                'age' => '20'
               [2]=> (array)
                'user' => 'john'
                'age' => '23'
              

              并且您想删除重复项...然后:

              $serialized = array();
              for ($i=0; $i < sizeof($users); $i++) { 
                $test = in_array($users['user'], $serialized);
                  if ($test == false) {
                    $serialized[] = $users['user'];
                  }
               }
              

              可能是一个解决方案:P

              【讨论】:

                【解决方案12】:

                很多人问我如何制作唯一的多维数组。我参考了您的评论,这对我有帮助。

                首先,感谢@jeromegamez @daveilers 的解决方案。但是每次我给出答案时,他们都会问我“序列化”和“反序列化”是如何工作的。这就是为什么我想和你分享这个的原因,以便帮助更多的人理解这背后的概念。

                我正在解释为什么我们在步骤中使用“序列化”和“反序列化”:

                第一步:将多维数组转换为一维数组

                要将多维数组转换为一维数组,首先要生成数组内部所有元素(包括嵌套数组)的字节流表示。 serialize() 函数可以生成一个值的字节流表示。要生成所有元素的字节流表示,请在 array_map() 函数中调用 serialize() 函数作为回调函数。无论多维数组有多少层,结果都是一维数组。

                第 2 步:使值独一无二

                要使这个一维数组唯一,请使用 array_unique() 函数。

                第三步:还原为多维数组

                虽然数组现在是唯一的,但值看起来像字节流表示。要将其恢复为多维数组,请使用 unserialize() 函数。

                $input = array_map("unserialize", array_unique(array_map("serialize", $input)));
                

                再次感谢这一切。

                【讨论】:

                  【解决方案13】:

                  一个易于阅读的解决方案,可能不是最有效的:

                  function arrayUnique($myArray){
                      if(!is_array($myArray))
                          return $myArray;
                  
                      foreach ($myArray as &$myvalue){
                          $myvalue=serialize($myvalue);
                      }
                  
                      $myArray=array_unique($myArray);
                  
                      foreach ($myArray as &$myvalue){
                          $myvalue=unserialize($myvalue);
                      }
                  
                      return $myArray;
                  
                  } 
                  

                  【讨论】:

                    【解决方案14】:

                    正如人们所说的array_unique() 非常慢,这是我用于一级多维数组的sn-p。

                    $serialized_array = array_map("serialize", $input);
                    
                    foreach ($serialized_array as $key => $val) {
                         $result[$val] = true;
                    }
                    
                    $output = array_map("unserialize", (array_keys($result)));
                    

                    参考array_unique()function page in php.net的第一个用户提供的注释

                    【讨论】:

                    • Anuj,你能编辑你的答案吗?有一个错误。它应该结束$output = array_map('unserialize', array_keys($result));
                    • @keyboardSmasher 感谢您的意见。我进行了更改,现在它可以工作了。 :)
                    【解决方案15】:

                    序列化和唯一性的替代方法

                    $test = [
                        ['abc','def'],
                        ['ghi','jkl'],
                        ['mno','pql'],
                        ['abc','def'],
                        ['ghi','jkl'],
                        ['mno','pql'],
                    ];
                    
                    $result = array_reduce(
                        $test,
                        function($carry,$item){
                            if(!in_array($item,$carry)) {
                                array_push($carry,$item);
                            }
                            return $carry;
                        },
                        []
                    );
                    
                    var_dump($result);
                    
                    /*
                     php unique.php
                    array(3) {
                        [0] =>
                            array(2) {
                                [0] =>
                                    string(3) "abc"
                                [1] =>
                                    string(3) "def"
                            }
                        [1] =>
                            array(2) {
                                [0] =>
                                    string(3) "ghi"
                                [1] =>
                                    string(3) "jkl"
                            }
                        [2] =>
                            array(2) {
                                  [0] =>
                                      string(3) "mno"
                                  [1] =>
                                      string(3) "pql"
                            }
                    }
                    

                    */

                    【讨论】:

                      【解决方案16】:

                      如果你有这样的数组

                      data = array
                      (
                      [0] => array
                      (
                          [subject] => a
                          [object] => c
                      ),
                      [1] => array
                      (
                          [subject] => b
                          [object] => d
                      ),
                      [2] => array
                      (
                          [subject] => d
                          [object] => b
                      ),
                      [3] => array
                      (
                          [subject] => d
                          [object] => c
                      ),
                      [4] => array
                      (
                          [subject] => c
                          [object] => a
                      ),
                      [5] => array
                      (
                          [subject] => c
                          [object] => d
                      )
                      )
                      

                      你想得到这样的数组:

                      data = array
                      (
                      [0] => array
                      (
                          [subject] => a
                          [object] => c
                      ),
                      [1] => array
                      (
                          [subject] => b
                          [object] => d
                      ),
                      [2] => array
                      (
                          [subject] => d
                          [object] => c
                      )
                      )
                      

                      data = array
                      (
                      [0] => array
                      (
                          [subject] => d
                          [object] => b
                      ),
                      [1] => array
                      (
                          [subject] => c
                          [object] => a
                      ),
                      [2] => array
                      (
                          [subject] => c
                          [object] => d
                      )
                      )
                      

                      以下代码可以提供帮助

                          $data1 = array();
                          $data1 = $data;
                          for($q=0;$q<count($data);$q++)
                          {
                                  for($p=0;$p<count($data1);$p++)
                                  {
                                          if (($data[$q]["subject"] == $data1[$p]["object"]) && ($data[$q]["object"] == $data1[$p]["subject"]))
                                          {
                                                  $data1[$p]["subject"] = $data[$q]["subject"];
                                                  $data1[$p]["object"] = $data[$q]["object"];
                                          }
                                  }
                          }
                          $data1 = array_values(array_map("unserialize", array_unique(array_map("serialize", $data1))));
                          $data = $data1;
                      

                      【讨论】:

                        【解决方案17】:

                        我对这个问题进行了深思熟虑,并确定最佳解决方案应遵循两条规则。

                        1. 为了可扩展性,就地修改阵列;不复制到新数组
                        2. 为了提高性能,每次比较只能进行一次

                        考虑到这一点并考虑到 PHP 的所有怪癖,下面是我想出的解决方案。与其他一些答案不同,它能够根据您想要的任何键删除元素。输入数组应为数字键。

                        $count_array = count($input);
                        for ($i = 0; $i < $count_array; $i++) {
                            if (isset($input[$i])) {
                                for ($j = $i+1; $j < $count_array; $j++) {
                                    if (isset($input[$j])) {
                                        //this is where you do your comparison for dupes
                                        if ($input[$i]['checksum'] == $input[$j]['checksum']) {
                                            unset($input[$j]);
                                        }
                                    }
                                }
                            }
                        }
                        

                        唯一的缺点是迭代完成时键不按顺序排列。如果您随后只使用 foreach 循环,这不是问题,但如果您需要使用 for 循环,您可以在上面添加 $input = array_values($input); 以重新编号键。

                        【讨论】:

                          【解决方案18】:

                          根据标记为正确的答案,添加我的答案。添加的小代码只是为了重置索引-

                          $input = array_values(array_map("unserialize", array_unique(array_map("serialize", $inputArray))));
                          

                          【讨论】:

                          • @milic 6 年前的回答展示了如何用array_values() 包装嵌套函数调用。我认为不需要添加此答案。您可以在接受的答案下添加评论说“如果您想重新索引结果,只需致电 array_values()”。
                          猜你喜欢
                          • 2017-06-01
                          • 2011-04-05
                          • 1970-01-01
                          • 2018-01-18
                          • 2017-07-23
                          • 1970-01-01
                          • 1970-01-01
                          • 1970-01-01
                          相关资源
                          最近更新 更多