5

I have two 2-dimensional arrays and want to filter the first array's data using the second array so that the only elements retained are where the keys in the first and second levels match.

$array1 = [
    'a1' => ['a_name' => 'aaaaa', 'a_value' => 'aaa'],
    'b1' => ['b_name' => 'bbbbb', 'b_value' => 'bbb'],
    'c1' => ['c_name' => 'ccccc', 'c_value' => 'ccc'],
];

$array2 = [
    'b1' => ['b_name' => 'does not matter'],
];

In other words, I want the intersection of keys of $array1 and $array2. The result must be from $array1.

Desired result:

['b1' => ['b_name' => 'bbbbb']]
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
kcssm
  • 1,727
  • 3
  • 16
  • 19

5 Answers5

11
function recursive_array_intersect_key(array $array1, array $array2) {
    $array1 = array_intersect_key($array1, $array2);
    foreach ($array1 as $key => &$value) {
        if (is_array($value) && is_array($array2[$key])) {
            $value = recursive_array_intersect_key($value, $array2[$key]);
        }
    }
    return $array1;
}

Demo here.

Community
  • 1
  • 1
deceze
  • 510,633
  • 85
  • 743
  • 889
  • How to do this if first is index array and second sub array is associative array? – FSShaikh Jan 05 '16 at 10:55
  • You need to check if the second parameter is an array as well to prevent type error(sending non-array values to back to the function) when the value is an array like this: ´if (is_array($value) && is_array($array2[$key])) {´ – Pelmered Jul 29 '16 at 09:59
  • Hi @deceze, how to add $array2 both are matching and not matching to $array2 – jvk Aug 22 '18 at 05:47
0
$output = array_intersect_key($array1, $array2);
Stegrex
  • 4,004
  • 1
  • 17
  • 19
0

Demo of 2 dimensional associative array intersection in PHP

The Code:

<?php
    function compare_states($a1, $a2){
        $diff1 = strcasecmp($a1['state_id'], $a2['state_id']);
        $diff2 = strcasecmp($a1['state_name'], $a2['state_name']);
        if ($diff1 != 0) return $diff1;
        if ($diff2 != 0) return $diff2;
        return 0;
    }
    function calculate_intersection($a1, $a2){
        return array_uintersect($a1, $a2, 'compare_states');
    }
?>

How to run it:

<?php
    $a = Array(Array("state_id"=>14, "state_name"=>"Illinois"));
    $b = Array(Array("state_id"=>14, "state_name"=>"Illinois"));
    $new = calculate_intersection($a, $b);
    print_r($a);
    //in this simple case, the intersection is equivalent to $a.
    $a = Array(Array("state_id"=>14, "state_name"=>"Illinois"));
    $b = Array(Array("state_id"=>14, "state_name"=>"Foobar"));
    $new = calculate_intersection($a, $b);
    print_r($a);
    //in this case, the intersection is empty.
?>

Unit tests to prove that the above code works as designed:

$a = Array();
$b = Array();
$new = calculate_intersection($a, $b);
print "\nGroup1\n";
print ((count($new) == count($a) && count($a) == count($b)) ? "." : "FAIL");
print ((count($new) == 0) ? "." : "FAIL");
//==============================================
$a = Array(Array("state_id"=>14, "state_name"=>"Illinois"));
$b = Array(Array("state_id"=>14, "state_name"=>"Illinois"));
$new = calculate_intersection($a, $b);
print "\nGroup2\n";
print ((count($new) == count($a) && count($a) == count($b)) ? "." : "FAIL");
print ((count($new) == 1) ? "." : "FAIL");
print (($new[0]['state_id'] == 14 ? "." : "FAIL"));
print (($new[0]['state_name'] == "Illinois" ? "." : "FAIL"));
//==============================================
print "\nGroup3\n";
$a = Array(Array("state_id"=>14, "state_name"=>"Illinois"), Array("state_id"=> "22", "state_name"=>"Massachusetts"));
$b = Array(Array("state_id"=>14, "state_name"=>"Illinois"), Array("state_id"=> "22", "state_name"=>"Massachusetts"));
$new = calculate_intersection($a, $b);
print ((count($new) == count($a) && count($a) == count($b)) ? "." : "FAIL");
print (($new[0]['state_id'] == 14 ? "." : "FAIL"));
print (($new[0]['state_name'] == "Illinois" ? "." : "FAIL"));
print (($new[1]['state_id'] == 22 ? "." : "FAIL"));
print (($new[1]['state_name'] == "Massachusetts" ? "." : "FAIL"));
//==============================================
$a = Array(Array("state_id"=>"14", "state_name"=>"Illinois"));
$b = Array(Array("state_id"=>"22", "state_name"=>"Massachusetts"));
$new = calculate_intersection($a, $b);
print "\nGroup5\n";
print ((count($new) == 0) ? "." : "FAIL");
//==============================================
$a = Array(Array("state_id"=>"14", "state_name"=>"Illinois"));
$b = Array(Array("state_id"=>"14", "state_name"=>"Illinois"), Array("state_id"=>"22", "state_name"=>"Massachusetts"));
$new = calculate_intersection($a, $b);
print "\nGroup6\n";
print ((count($new) == 1) ? "." : "FAIL");
print (($new[0]['state_id'] == 14) ? "." : "FAIL");
print (($new[0]['state_name'] == "Illinois") ? "." : "FAIL");
//==============================================
$a = Array(Array("state_id"=>"14", "state_name"=>"Illinois"));
$b = Array(Array("state_id"=>"22", "state_name"=>"Massachusetts"), Array("state_id"=>"14", "state_name"=>"Illinois"));
$new = calculate_intersection($a, $b);
print "\nGroup7\n";
print ((count($new) == 1) ? "." : "FAIL");
print (($new[0]['state_id'] == 14) ? "." : "FAIL");
print (($new[0]['state_name'] == "Illinois") ? "." : "FAIL");
//==============================================
$a = Array(Array("state_id"=>"14", "state_name"=>"Illinois"));
$b = Array(Array("state_id"=>"22", "state_name"=>"Massachusetts"), Array("state_id"=>"14", "state_name"=>"Fromulate"));
$new = calculate_intersection($a, $b);
print "\nGroup8\n";
print ((count($new) == 0) ? "." : "FAIL");
//==============================================
$a = Array(Array("state_id"=>"14", "state_name"=>"Illinois"), Array("state_id"=>"14", "state_name"=>"Illinois"));
$b = Array(Array("state_id"=>"14", "state_name"=>"Illinois"), Array("state_id"=>"14", "state_name"=>"Illinois"));
$new = calculate_intersection($a, $b);
print "\nGroup9\n";
print ((count($new) == 2) ? "." : "FAIL");
print (($new[0]['state_id'] == 14) ? "." : "FAIL");
print (($new[0]['state_name'] == "Illinois") ? "." : "FAIL");
print (($new[1]['state_id'] == 14) ? "." : "FAIL");
print (($new[1]['state_name'] == "Illinois") ? "." : "FAIL");
//==============================================
$a = Array(Array("state_id"=>"14", "state_name"=>"Illinois"), Array("state_id"=>"22", "state_name"=>"Massachusetts"));
$b = Array(Array("state_id"=>"22", "state_name"=>"Massachusetts"), Array("state_id"=>"14", "state_name"=>"Illinois"));
$new = calculate_intersection($a, $b);
print "\nGroup7\n";
print ((count($new) == 2) ? "." : "FAIL");
print (($new[0]['state_id'] == 14) ? "." : "FAIL");
print (($new[0]['state_name'] == "Illinois") ? "." : "FAIL");
print (($new[1]['state_id'] == 22) ? "." : "FAIL");
print (($new[1]['state_name'] == "Massachusetts") ? "." : "FAIL");
?>

The above code prints:

eric@dev $ php a.php
Group1
..
Group2
....
Group3
.....
Group5
.
Group6
...
Group7
...
Group8
.
Group9
.....
Group7
.....

All dots means everything passed.

What cases does this code take care of?

  1. Both arrays being empty. Intersection is empty.
  2. One empty and the other with items. Intersection is empty.
  3. Both arrays have identical items, set: 1 and set: n. Intersection is equivalent to the first array.
  4. Both arrays are identical, except shuffled. Intersection is equivalent to first array.
  5. The arrays are identical except the state_name is different in each case, and the state_id is the same. Intersection is empty.
  6. Array a has items uncommon to b, items common to B. Array b has items uncommon to a and items common to A. Intersection is the items common to both a and b.

What it doesn't do:

It doesn't test for nulls/undefined/dissimilar depth arrays, nor arrays 2 or more layers deep. If datatypes get swapped, comparing strings to ints, or floats to octals, it will probably fail. It's difficult to get PHP to do equality correctly. http://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/

Do everything you can to try to do this work in the database, doing it in PHP blows the horn to summon the fail whale. It's inefficient, so you better not be operating on more than a few hundred items. It's going to surprise left jab you on unexpected cases, and it's kind of hard to read/understand what it's doing under the hood.

Eric Leschinski
  • 146,994
  • 96
  • 417
  • 335
  • To prove that your answer works as expected, it's generally a good idea to execute your code with the two provided associative arrays of associative arrays. If your code is respecting first level keys, I'm not seeing where that is happening. Perhaps [edit] your answer to demonstrate with the asker's data. – mickmackusa Aug 24 '22 at 07:28
0

Because you are filtering arrays of consistent depth, recursion is not explicitly required.

  • Filter on the first level keys with array_intersect_key().
  • Then filter each related row (the second level elements) between the two arrays.
  • If there are no intersections in a given row, remove the first level key as well -- because the requirement of this question is to only keep the data that matches the first AND second level keys.

Code: (Demo)

$array1 = [
    'a1' => ['a_name' => 'aaaaa', 'a_value' => 'aaa'],
    'b1' => ['b_name' => 'bbbbb', 'b_value' => 'bbb'],
    'c1' => ['c_name' => 'ccccc', 'c_value' => 'ccc'],
];

$array2 = [
    'b1' => ['b_name' => 'bbbbb'],
    'c1' => ['a_value' => 'aaa']
];


$result = array_intersect_key($array1, $array2);
foreach ($result as $key => &$value) {
    $value = array_intersect_key($value, $array2[$key]);
    if (!$value) {
        unset($result[$key]);
    }
}
var_export($result);

Output:

array (
  'b1' => 
  array (
    'b_name' => 'bbbbb',
  ),
)
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
-1

I think you should check if the $array2[$key] is an array, too.

function recursive_array_intersect_key(array $array1, array $array2) {
    $array1 = array_intersect_key($array1, $array2);
    foreach ($array1 as $key => &$value) {
        if (is_array($value) && is_array($array2[$key])) {
            $value = recursive_array_intersect_key($value, $array2[$key]);
        }
    }
    return $array1;
}
  • Your advice was taken on by deceze and he has edited his answer. You can safely remove this adjusted version of his original code. – mickmackusa Aug 24 '22 at 07:30