Get the keys for duplicate values in an array

Viewed 37975

I have the following array:

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

Result:

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. Now how can I display the keys with duplicate values? Here the function should NOT return ([0],[9]) since there are no duplicates with the values.
  2. How to find the keys for the same value, eg. for "2011-06-25" it should return [7],[8]
11 Answers

Another example:

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

Output:

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 ) 

Here's another solution for question 1 that I have used to get duplicates in a one-dimensional array:

Taking for example this array:

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

I like to avoid loops if possible, so I used array_map to solve this problem:

/**
 * 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()

The array_map function loops every unique element of the $list and uses the original $list to get the array keys of occurrences with array_keys($list, $el). If the resulting occurrence count is more than 1, the index is returned of all the occurrences and replaces the original $el with the array of indices. Otherwise null is returned, which also replaces the $el in the unique variant of $list. Finally the resulting array is filtered for empty values (as is the case with null values). Resulting in the following array:

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

Use a classic foreach() to unconditionally group&push a newly structured array with all values as keys and all keys as indexed elements in the group's subarray. In my snippet below, I'll use a body-less foreach because it is valid syntax to push the key value where it would otherwise be declared as a temporary variable. (read more here: Within a foreach() expression, is the value defined before or after the key?)

Then to filter out the dates that only have one element, call the native array_key_last() function to remove date entries where the highest index in the subarray is 0.

Code: (Demo)

$result = [];
foreach ($myarray as $result[$v][] => $v);
var_export(array_filter($result, 'array_key_last'));

Output:

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

Like many other answers on this page, this technique will not be suitable for any data types that cannot become keys (such as iterable type data) or that lose data integrity when assigned as a key (such as float type data).

Related