micadelli
micadelli

Reputation: 2482

Find all array keys that has same value

Is there a simpler way to get all array keys that has same value, when the value is unknown.

The problem with array_unique is that it returns the unique array and thus it doesn't find unique values.

That is, for example, from this array:

Array (
  [a]=>1000
  [b]=>1
  [c]=>1000
)

I want to get this

Array (
  [a]=>1000
  [c]=>1000
)

Another way around this is, if I could find the lonely values, and then their keys, and then use array_diff

This is what I've got so far, looks awful:

$a = array( 'a' => 1000, 'b' => 1, 'c' => 1000 );
$b = array_flip( array_count_values( $a ) );
krsort( $b );
$final = array_keys( $a, array_shift( $b ) );

Update
Using Paulo Freites' answer as a code base, I could get it working pretty easily, maintainable and easy on eyes kind of way… by using the filtering as a static class method I can get the duplicate values from an array by just calling ClassName::get_duplicates($array_to_filter)

private static $counts = null;

private static function filter_duplicates ($value) {
    return self::$counts[ $value ] > 1;
}

public static function get_duplicates ($array) {
    self::$counts = array_count_values( $array );
    return array_filter( $array, 'ClassName::filter_duplicates' );
}

Upvotes: 2

Views: 22730

Answers (6)

Jyothi
Jyothi

Reputation: 73

$array = array("1"=>"A","2"=>"A","3"=>"A","4"=>"B","5"=>"B","6"=>"B");
$val   = array_unique(array_values($array));
foreach ($val As $v){
  $dat[$v] = array_keys($array,$v);
}
print_r($dat);

Upvotes: 0

abfurlan
abfurlan

Reputation: 415

Try this

$a = array( 'a' => 1, 'b' => 1000, 'c' => 1000,'d'=>'duplicate','e'=>'duplicate','f'=>'ok','g'=>'ok' );
$b = array_map("unserialize", array_unique(array_map("serialize", $a)));
$c = array_diff_key($a, $b);

Upvotes: 1

Paulo Freitas
Paulo Freitas

Reputation: 13649

Taking advantage of closures for a more straightforward solution:

$array = array('a' => 1000, 'b' => 1, 'c' => 1000);
$counts = array_count_values($array);
$filtered = array_filter($array, function ($value) use ($counts) {
    return $counts[$value] > 1;
});
var_dump($filtered);

This gave me the following:

array(2) {
  ["a"]=>
  int(1000)
  ["c"]=>
  int(1000)
}

Demo: https://eval.in/67526

That's all! :)

Update: backward-compatible solution

$array = array('a' => 1000, 'b' => 1, 'c' => 1000);
$counts = array_count_values($array);
$filtered = array_filter($array, create_function('$value',
    'global $counts; return $counts[$value] > 1;'));
var_dump($filtered);

Demo: https://eval.in/68255

Upvotes: 7

Wh1T3h4Ck5
Wh1T3h4Ck5

Reputation: 8509

at the moment I cant figure out another solution...

  // target array
  $your_array = array('a'=>1000, 'b'=>1, 'c'=>1000);

  // function to do all the job
  function get_duplicate_elements($array) {
    $res = array();
    $counts = array_count_values($array);
    foreach ($counts as $id=>$count) {
     if ($count > 1) {
       $r = array();
       $keys = array_keys($array, $id);
       foreach ($keys as $k) $r[$k] = $id;
       $res[] = $r;
       }
     }
    return sizeof($res) > 0 ? $res : false;
    }

  // test it
  print_r(get_duplicate_elements($your_array));

output:

Array
(
    [0] => Array
        (
            [a] => 1000
            [c] => 1000
        )

)

example #2: - when you have different values multiplied

// target array
$your_array = array('a'=>1000, 'b'=>1, 'c'=>1000, 'd'=>500, 'e'=>1);

// output
print_r(get_duplicate_elements($your_array));

output:

Array
(
    [0] => Array
        (
            [a] => 1000
            [c] => 1000
        )

    [1] => Array
        (
            [b] => 1
            [e] => 1
        )

)

if function result has been assigned to $res variable $res[0] gets an array of all elements from original array with first value found more than once, $res[1] gets array of elements with another duplicated-value, etc... function returns false if nothing duplicate has been found in argument-array.

Upvotes: 1

SamV
SamV

Reputation: 7586

If you want to get the duplicates in an array try this:

array_unique(array_diff_assoc($array1, array_unique($array1)))

I found this from:

http://www.php.net/manual/en/function.array-unique.php#95203

Upvotes: 1

Jonathan Kuhn
Jonathan Kuhn

Reputation: 15301

Your implementation has a few issues.

1) If there are 2 of value 1000 and 2 of another value, the array_flip will lose one of the sets of values.

2) If there are more than two different values, the array_keys will only find the one value that occurs most.

3) If there are no duplicates, you will still bring back one of the values.

Something like this works always and will return all duplicate values:

<?php
//the array
$a = array( 'a' => 1000, 'b' => 1, 'c' => 1000 );
//count of values
$cnt = array_count_values($a);

//a new array
$newArray = array();
//loop over existing array
foreach($a as $k=>$v){
    //if the count for this value is more than 1 (meaning value has a duplicate)
    if($cnt[$v] > 1){
        //add to the new array
        $newArray[$k] = $v;
    }
}

print_r($newArray);

http://codepad.viper-7.com/fal5Yz

Upvotes: 4

Related Questions