【问题标题】:Get the keys for duplicate values in an array获取数组中重复值的键
【发布时间】:2011-09-21 14:31:12
【问题描述】:

我有以下数组:

$myarray = Array("2011-06-21", "2011-06-22", "2011-06-22", "2011-06-23", "2011-06-23", "2011-06-24", "2011-06-24", "2011-06-25", "2011-06-25", "2011-06-26");
var_dump($myarray);

结果:

Array (
    [0] => 2011-06-21
    [1] => 2011-06-22
    [2] => 2011-06-22
    [3] => 2011-06-23
    [4] => 2011-06-23
    [5] => 2011-06-24
    [6] => 2011-06-24
    [7] => 2011-06-25
    [8] => 2011-06-25
    [9] => 2011-06-26
)
  1. 现在如何显示具有重复值的键?此处函数不应返回 ([0],[9]),因为这些值没有重复项。
  2. 如何找到相同值的键,例如。对于“2011-06-25”,它应该返回 [7],[8]

【问题讨论】:

    标签: php arrays duplicates key


    【解决方案1】:
    function get_keys_for_duplicate_values($my_arr, $clean = false) {
        if ($clean) {
            return array_unique($my_arr);
        }
    
        $dups = $new_arr = array();
        foreach ($my_arr as $key => $val) {
          if (!isset($new_arr[$val])) {
             $new_arr[$val] = $key;
          } else {
            if (isset($dups[$val])) {
               $dups[$val][] = $key;
            } else {
               $dups[$val] = array($key);
               // Comment out the previous line, and uncomment the following line to
               // include the initial key in the dups array.
               // $dups[$val] = array($new_arr[$val], $key);
            }
          }
        }
        return $dups;
    }
    

    显然函数名有点长;)

    现在 $dups 将包含一个由重复值作为键的多维数组,其中包含重复的每个键,如果您发送“true”作为第二个参数,它将返回没有重复值的原始数组。

    或者,您可以将原始数组作为参考传递,它会在返回重复数组时相应地调整它

    【讨论】:

    • 你可以通过将if ($clean === true) { return array_unique($my_arr); }放在顶部来缩短$clean === true时的代码路径;)
    • 顺便说一下,到目前为止我测试过的最快的方法,每次迭代大约需要 0.04463 秒处理 100,000+ 元素数组的 100 次迭代!
    • 稍微改变了我的测试方法,虽然仍然最快,但实际迭代时间接近 0.1811 秒;该数组(平均)有 165,000 个元素,其中 100,000 个元素是唯一的。
    • 也许这不是函数的意图,但该函数也返回非重复值。只是想提一下这个。我做了一个foreach ($dups as $k=>$v) { if( count($v) == 1) unset($dups[$k]); } 来解决这个问题,但我认为这不是很有效。
    • 糟糕,出现逻辑问题,应该是if(!isset($new_arr[$val])),我已修复,现在应该可以正常工作了
    【解决方案2】:
    $array = array(0 => "1", 1 => "1", 2 => "2", 3 => "3");
    $count = array();
    foreach($array as $key => $value) {
      if(!isset($count[$value])) {
        $count[$value] = 0;
      }
      $count[$value]++;
    }
    
    
    $result = array_filter($count, function($value) {
      return $value > 1;
    });
    
    $result = array_keys($result);
    
    var_dump($result);
    

    输出

    array(1) {
      [0]=>
      int(1)
    }
    

    【讨论】:

      【解决方案3】:

      这是一个代码老兄

         $your_array = array(0 => '2011-06-21', 1 => '2011-06-22', 2 => '2011-06-22', 3 => '2011-06-23', 4 =>
      '2011-06-23', 5 => '2011-06-24', 6 => '2011-06-24', 7 => '2011-06-25', 8 => '2011-06-25', 9 
      => '2011-06-26', 10 => '2011-06-26', 11 => '2011-06-27', 12 => '2011-06-27', 13 => '2011-06-  
      28', 14 => '2011-06-29', 15 => '2011-06-29', 16 => '2011-06-30', 17 => '2011-06-30', 18 => 
      '2011-07-01', 19 => '2011-07-01', 20 => '2011-07-02', 21 => '2011-07-02', 22 => '2011-07-03', 
      23 => '2011-07-03', 24 => '2011-07-04', 25 => '2011-07-04', 26 => '2011-07-05', 27 => '2011-
      07-05', 28 => '2011-07-06', 29 => '2011-07-06', 30 => '2011-07-07', 31 => '2011-07-07');
      
      $keys_of_duplicated = array();
      $array_keys = array();
      
      foreach($your_array as $key => $value) {
          //- get the keys of the actual value
          $array_keys = array_keys($your_array, $value);
      
          //- if there is more then one key collected we register it
          if(count($array_keys) > 1) {
              //- foreach key that have the same value we check if i'ts already registered
              foreach($array_keys as $key_registered) {
                  //- if not registered we register it
                  if(!in_array($key_registered,  $keys_of_duplicated)) {
                       $keys_of_duplicated[] = $key_registered;
                  }
              }
          }
      }
      
      var_dump($keys_of_duplicated);
      

      $keys_of_duplicated 现在是包含重复数组键的数组;)再见

      【讨论】:

      • 在我的测试中,在一个足够大的数组(我的测试中为 100,000)上超时(60 秒)。
      【解决方案4】:

      我先回答第二个问题。您想使用 array_keys 并指定“search_value”。

      $keys = array_keys($array, "2011-06-29")
      

      在下面的示例中,$duplicates 将包含重复值,而$result 将包含非重复值。要获取密钥,只需使用array_keys

      <?php
      
      $array = array(
        'a',
        'a',
        'b',
        'c',
        'd'
      );
      
      // Unique values
      $unique = array_unique($array);
      
      // Duplicates
      $duplicates = array_diff_assoc($array, $unique);
      
      // Unique values
      $result = array_diff($unique, $duplicates);
      
      // Get the unique keys
      $unique_keys = array_keys($result);
      
      // Get duplicate keys
      $duplicate_keys = array_keys(array_intersect($array, $duplicates));
      

      结果:

      // $duplicates
      Array
      (
          [1] => a
      )
      
      // $result
      Array
      (
          [2] => b
          [3] => c
          [4] => d
      )
      
      // $unique_keys
      Array
      (
          [0] => 2
          [1] => 3
          [2] => 4
      )
      
      // $duplicate_keys
      Array
      (
          [0] => 0
          [1] => 1
      )
      

      【讨论】:

      • 这将返回值,而不是键。
      • @cypher - 你是对的。我忘了包括array_keys。我已经更新了我的答案。
      • 另外,有趣的问题是他是否想打印出所有重复的键 - 在你的情况下 01a
      • @cypher - 一个简单的array_keys(array_intersect($array, $duplicates)) 就可以做到这一点。 :)
      • +1 不错的答案。我喜欢独特/差异的方法。但是 OP 要求的不是唯一的,而是那些不唯一的键。因此,您可能不仅应该将其放入评论中,还应该将其放入您的答案中。
      【解决方案5】:
      $array = array(
          '2011-06-21','2011-06-22','2011-06-22','2011-06-23',
          '2011-06-23','2011-06-24','2011-06-24','2011-06-25',
          '2011-06-25','2011-06-26','2011-06-26','2011-06-27',
          '2011-06-27','2011-06-28','2011-06-29','2011-06-29',
          '2011-06-30','2011-06-30','2011-07-01','2011-07-01',
          '2011-07-02','2011-07-02','2011-07-03','2011-07-03',
          '2011-07-04','2011-07-04','2011-07-05','2011-07-05',
          '2011-07-06','2011-07-06','2011-07-07','2011-07-07',
      );
      
      function getDupKeys(array $array, $return_first = true, $return_by_key = true) {
          $seen = array();
          $dups = array();
      
          foreach ($array as $k => $v) {
              $vk = $return_by_key ? $v : 0;
              if (!array_key_exists($v, $seen)) {
                  $seen[$v] = $k;
                  continue;
              }
              if ($return_first && !array_key_exists($v, $dups)) {
                  $dups[$vk][] = $seen[$v];
              }
              $dups[$vk][] = $k;
          }
          return $return_by_key ? $dups : $dups[0];
      }
      

      如果两个可选参数都为真,则返回一个数组数组;每个子数组的键将是不唯一的值,数组的值将是具有该值的所有键。

      如果第一个可选参数为假,则只有键之后会返回非唯一值的第一个实例(即,对于给定的数组,每个值只返回一个键,第二次发生,而不是第一次)。

      如果第二个参数是可选的,那么它不会返回一个数组数组,而是返回一个包含所有重复键的平面数组(它返回的确切键是由前面的可选参数决定的)。

      这是一个 dumpprint_r,因为它更漂亮:

      print_r(getDupKeys($array));
      
      Array
      (
          [2011-06-22] => Array
              (
                  [0] => 1
                  [1] => 2
              )
      
          [2011-06-23] => Array
              (
                  [0] => 3
                  [1] => 4
              )
      
          [2011-06-24] => Array
              (
                  [0] => 5
                  [1] => 6
              )
      
          [2011-06-25] => Array
              (
                  [0] => 7
                  [1] => 8
              )
      
          [2011-06-26] => Array
              (
                  [0] => 9
                  [1] => 10
              )
      
          [2011-06-27] => Array
              (
                  [0] => 11
                  [1] => 12
              )
      
          [2011-06-29] => Array
              (
                  [0] => 14
                  [1] => 15
              )
      
          [2011-06-30] => Array
              (
                  [0] => 16
                  [1] => 17
              )
      
          [2011-07-01] => Array
              (
                  [0] => 18
                  [1] => 19
              )
      
          [2011-07-02] => Array
              (
                  [0] => 20
                  [1] => 21
              )
      
          [2011-07-03] => Array
              (
                  [0] => 22
                  [1] => 23
              )
      
          [2011-07-04] => Array
              (
                  [0] => 24
                  [1] => 25
              )
      
          [2011-07-05] => Array
              (
                  [0] => 26
                  [1] => 27
              )
      
          [2011-07-06] => Array
              (
                  [0] => 28
                  [1] => 29
              )
      
          [2011-07-07] => Array
              (
                  [0] => 30
                  [1] => 31
              )
      
      )
      

      print_r(getDupKeys($array, false));
      
      Array
      (
          [2011-06-22] => Array
              (
                  [0] => 2
              )
      
          [2011-06-23] => Array
              (
                  [0] => 4
              )
      
          [2011-06-24] => Array
              (
                  [0] => 6
              )
      
          [2011-06-25] => Array
              (
                  [0] => 8
              )
      
          [2011-06-26] => Array
              (
                  [0] => 10
              )
      
          [2011-06-27] => Array
              (
                  [0] => 12
              )
      
          [2011-06-29] => Array
              (
                  [0] => 15
              )
      
          [2011-06-30] => Array
              (
                  [0] => 17
              )
      
          [2011-07-01] => Array
              (
                  [0] => 19
              )
      
          [2011-07-02] => Array
              (
                  [0] => 21
              )
      
          [2011-07-03] => Array
              (
                  [0] => 23
              )
      
          [2011-07-04] => Array
              (
                  [0] => 25
              )
      
          [2011-07-05] => Array
              (
                  [0] => 27
              )
      
          [2011-07-06] => Array
              (
                  [0] => 29
              )
      
          [2011-07-07] => Array
              (
                  [0] => 31
              )
      
      )
      

      print_r(getDupKeys($array, true, false));
      
      Array
      (
          [0] => 1
          [1] => 2
          [2] => 3
          [3] => 4
          [4] => 5
          [5] => 6
          [6] => 7
          [7] => 8
          [8] => 9
          [9] => 10
          [10] => 11
          [11] => 12
          [12] => 14
          [13] => 15
          [14] => 16
          [15] => 17
          [16] => 18
          [17] => 19
          [18] => 20
          [19] => 21
          [20] => 22
          [21] => 23
          [22] => 24
          [23] => 25
          [24] => 26
          [25] => 27
          [26] => 28
          [27] => 29
          [28] => 30
          [29] => 31
      )
      

      print_r(getDupKeys($array, false, false));
      
      Array
      (
          [0] => 2
          [1] => 4
          [2] => 6
          [3] => 8
          [4] => 10
          [5] => 12
          [6] => 15
          [7] => 17
          [8] => 19
          [9] => 21
          [10] => 23
          [11] => 25
          [12] => 27
          [13] => 29
          [14] => 31
      )
      

      【讨论】:

        【解决方案6】:

        我真的很喜欢弗朗索瓦的回答,这是我想出的保留键的东西。我先回答第一个问题:

        $array = array('2011-06-21', '2011-06-22', '2011-06-22');
        /**
         * flip an array like array_flip but
         * preserving multiple keys per an array value
         * 
         * @param array $a
         * @return array
         */
        function array_flip_multiple(array $a) {
            $result = array();
            foreach($a as $k=>$v)
                $result[$v][]=$k
                ;
            return $result;
        }
        
        $hash = array_flip_multiple($array);
        
        // filter $hash based on your specs (2 or more)
        $hash = array_filter($hash, function($items) {return count($items) > 1;});
        
        // get all remaining keys
        $keys = array_reduce($hash, 'array_merge', array());
        
        var_dump($array, $hash, $keys);
        

        输出是:

        # original array
        array(3) {
          [0]=>
          string(10) "2011-06-21"
          [1]=>
          string(10) "2011-06-22"
          [2]=>
          string(10) "2011-06-22"
        }
        
        # hash (filtered)
        array(1) {
          ["2011-06-22"]=>
          array(2) {
            [0]=>
            int(1)
            [1]=>
            int(2)
          }
        }
        
        # the keys
        array(2) {
          [0]=>
          int(1)
          [1]=>
          int(2)
        }
        

        那么现在是第二个问题:

        只需使用$hash 获取值的键:

        var_dump($hash['2011-06-22']); 返回密钥。

        好处是,如果您需要检查多个值,数据已经存储在哈希中并可供使用。

        【讨论】:

          【解决方案7】:

          我遇到了与 OP 提出的问题 #1 类似的问题。我所需要的只是原始数组中重复值的键。这是我想出的:

          $array = array('yellow', 'red', 'green', 'brown', 'red', 'brown');
          
          $counts = array_count_values($array);
          $filtered = array_filter($counts, function($value) {
              return $value != 1;
          });
          $result = array_keys(array_intersect($array, array_keys($filtered)));
          

          对于输出:

          print_r($result);
          Array
          (
              [0] => 1
              [1] => 3
              [2] => 4
              [3] => 5
          )
          

          【讨论】:

            【解决方案8】:
            function getDuplicateValueKeys($my_arr, $clean = false) 
            {
                if ($clean) {
                    return array_unique($my_arr);
                }
                $dups = array();
                $new_arr = array();
                $dup_vals = array();
            
                foreach ($my_arr as $key => $value) {
                    if (!isset($new_arr[$value])) {
                        $new_arr[$value] = $key;
                    } else {
                        array_push($dup_vals,$value);
                    }
                }
            
                foreach ($my_arr as $key => $value) {
                    if (in_array($value, $dup_vals)) {
                        if (!isset($dups[$value])) {
                            $dups[$value]=array($key);
                        }else{
                            array_push($dups[$value],$key);
                        }
                    }
                }
            
                return $dups;
            }
            

            【讨论】:

              【解决方案9】:

              另一个例子:

              $array = array(
                'a',
                'a',
                'b',
                'b',
                'b'
              );
              echo '<br/>Array: ';
              print_r($array);
              // Unique values
              $unique = array_unique($array);
              echo '<br/>Unique Values: ';
              print_r($unique);
              // Duplicates
              $duplicates = array_diff_assoc($array, $unique);
              echo '<br/>Duplicates: ';
              print_r($duplicates);
              // Get duplicate keys
              $duplicate_values = array_values(array_intersect($array, $duplicates));
              echo '<br/>duplicate values: ';
              print_r($duplicate_values);
              

              输出:

              Array :Array ( [0] => a [1] => a [2] => b [3] => b [4] => b ) 
              Unique Values :Array ( [0] => a [2] => b ) 
              Duplicates :Array ( [1] => a [3] => b [4] => b ) 
              Duplicate Values :Array ( [0] => a [1] => a [2] => b [3] => b [4] => b ) 
              

              【讨论】:

                【解决方案10】:

                这是我用来在一维数组中获取重复项的问题 1 的另一个解决方案:

                以这个数组为例:

                $arr = ['a','b','c','d','a','a','b','c','c'];
                

                我喜欢尽可能避免循环,所以我使用array_map 来解决这个问题:

                /**
                 * Find multiple occurrences in a one-dimensional array
                 *
                 * @param array $list List to find duplicates for.
                 *
                 * @return array
                 */
                function fetchDuplicates(array $list)
                {
                    return array_filter(
                        array_map(
                            function ($el) use ($list) {
                                $keysOccur = array_keys($list, $el);
                                if (count($keysOccur) > 1) {
                                    return $keysOccur;
                                }
                
                                return null;
                            },
                            array_unique($list)
                        )
                    );
                
                }//end fetchDuplicates()
                

                array_map 函数循环$list 的每个唯一元素,并使用原始$list 来获取array_keys($list, $el) 出现的数组键。如果结果出现计数大于 1,则返回所有出现的索引,并将原始 $el 替换为索引数组。否则返回null,这也将替换$list 的唯一变体中的$el。最后,结果数组被过滤为空值(null 值就是这种情况)。产生以下数组:

                [
                  [
                    0,
                    4,
                    5,
                  ],
                  [
                    1,
                    6,
                  ],
                  [
                    2,
                    7,
                    8,
                  ],
                ]
                

                【讨论】:

                  猜你喜欢
                  • 2018-10-03
                  • 2016-05-30
                  • 2016-12-02
                  • 2020-01-06
                  • 1970-01-01
                  • 1970-01-01
                  • 2020-11-11
                  • 2011-04-14
                  • 2019-12-09
                  相关资源
                  最近更新 更多