8

I'd like to merge two arrays with each other:

$filtered = array(1 => 'a', 3 => 'c');
$changed = array(2 => 'b*', 3 => 'c*');

Whereas the merge should include all elements of $filtered and all those elements of $changed that have a corresponding key in $filtered:

$merged = array(1 => 'a', 3 => 'c*');

array_merge($filtered, $changed) would add the additional keys of $changed into $filtered as well. So it does not really fit.

I know that I can use $keys = array_intersect_key($filtered, $changed) to get the keys that exist in both arrays which is already half of the work.

However I'm wondering if there is any (native) function that can reduce the $changed array into an array with the $keys specified by array_intersect_key? I know I can use array_filter with a callback function and check against $keys therein, but there is probably some other purely native function to extract only those elements from an array of which the keys can be specified?

I'm asking because the native functions are often much faster than array_filter with a callback.

CharlesB
  • 86,532
  • 28
  • 194
  • 218
hakre
  • 193,403
  • 52
  • 435
  • 836

3 Answers3

20

This should do it, if I'm understanding your logic correctly:

array_intersect_key($changed, $filtered) + $filtered

Implementation:

$filtered = array(1 => 'a', 3 => 'c');
$changed = array(2 => 'b*', 3 => 'c*');
$expected = array(1 => 'a', 3 => 'c*');    
$actual = array_key_merge_deceze($filtered, $changed);

var_dump($expected, $actual);

function array_key_merge_deceze($filtered, $changed) {
    $merged = array_intersect_key($changed, $filtered) + $filtered;
    ksort($merged);
    return $merged;
}

Output:

Expected:
array(2) {
  [1]=>
  string(1) "a"
  [3]=>
  string(2) "c*"
}

Actual:
array(2) {
  [1]=>
  string(1) "a"
  [3]=>
  string(2) "c*"
}
hakre
  • 193,403
  • 52
  • 435
  • 836
deceze
  • 510,633
  • 85
  • 743
  • 889
  • Union against the intersection. But union will add keys of `$filtered` as well AFAIK. I'll give it a try. – hakre Jul 03 '11 at 10:21
  • Jup. I just tested it, my fault ;). It works pretty well, only the order of keys changes, but that's no problem as I have them as a numerical index, so ksort does the job. Perfect. Thanks a lot! – hakre Jul 03 '11 at 10:26
  • @deceze `array_intersect_key($changed, $filtered) + $filtered` Strange. I never seen that before. No idea what's happens here, but it works! What is the job for `+ $filtered` – The Bndr Apr 11 '14 at 07:54
  • 1
    @The `array_intersect_key($changed, $filtered)` takes all values from `$changed` which have a key in `$filtered`, i.e. it produces a subset of `$filtered` with the values from `$changed`. `+ $filtered` then adds the rest of the values from `$filtered` back into the result, i.e. it fills the subset back up to have all the keys in `$filtered`. – deceze Apr 11 '14 at 08:27
  • You may want to place a return `$changed` when `$filtered` is empty depending on your use case. – Goose May 17 '19 at 16:01
0

if you want the second array ($b) to be the pattern that indicates that if there is only the key there, then you could also try this

$new_array =  array_intersect_key( $filtered, $changed ) + $changed;
Lenin Zapata
  • 1,417
  • 1
  • 11
  • 14
0

If your keys are non-numeric (which yours are not, so this is not a solution to your exact question), then you can use this technique:

$filtered = array('a' => 'a', 'c' => 'c');
$changed = array('b' => 'b*', 'c' => 'c*');

$merged = array_slice(array_merge($filtered, $changed), 0, count($filtered));

Result:

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

This works because for non-numeric keys, array_merge overwrites values for existing keys, and appends the keys in $changed to the end of the new array. So we can simply discard any keys from the end of the merged array more than the count of the original array.

Since this applies to the same question but with different key types I thought I'd provide it.

If you use this with numeric keys then the result is simply the original array ($filtered in this case) with re-indexed keys (IE as if you used array_values).

Dan
  • 473
  • 3
  • 7