315

How can I merge two arrays (one with string => value pairs and another with int => value pairs) while keeping the string/int keys? None of them will ever overlap (because one has only strings and the other has only integers).

Here is my current code (which doesn't work, because array_merge is re-indexing the array with integer keys):

// get all id vars by combining the static and dynamic
$staticIdentifications = array(
 Users::userID => "USERID",
 Users::username => "USERNAME"
);
// get the dynamic vars, formatted: varID => varName
$companyVarIdentifications = CompanyVars::getIdentificationVarsFriendly($_SESSION['companyID']);
// merge the static and dynamic vars (*** BUT KEEP THE INT INDICES ***)
$idVars = array_merge($staticIdentifications, $companyVarIdentifications);
5
  • 1
    That's odd: according to the PHP doc page, array_merge shouldn't do that. Are the string keys actually string representations of integers? Commented Jul 20, 2010 at 16:16
  • array_merge is reindexing my second array. ie. it is changing the array from array( 123 => "VALUE123" ) to array( 0 => "VALUE123" ) Commented Jul 20, 2010 at 16:16
  • hmm, that is interesting. I suppose that the PHP documentation could be a little unclear on that point. It says what will happen if all of the arrays have numeric keys, but it doesn't specifically say what will happen if they don't. Commented Jul 20, 2010 at 16:25
  • maybe not 2 years ago. But in 2012, the documentation is Crystal clear on this point. Commented May 15, 2012 at 8:32
  • Actually, the documentation is still not crystal clear. "Numeric" actually includes a string with all digits (PHP 5.3.3). assert(array(0=>0,1=>1) === array_merge(array('9'=>0), array('9'=>1))) Commented Feb 11, 2013 at 3:27

6 Answers 6

653

You can simply 'add' the arrays:

>> $a = array(1, 2, 3);
array (
  0 => 1,
  1 => 2,
  2 => 3,
)
>> $b = array("a" => 1, "b" => 2, "c" => 3)
array (
  'a' => 1,
  'b' => 2,
  'c' => 3,
)
>> $a + $b
array (
  0 => 1,
  1 => 2,
  2 => 3,
  'a' => 1,
  'b' => 2,
  'c' => 3,
)
Sign up to request clarification or add additional context in comments.

4 Comments

Be VERY careful with this! The + operator is not an addition, it's a union. If the keys don't overlap then all is good, but if they do...
In case anyone wonders 'what if they DO overlap?' : php.net: "The + operator returns the right-hand array appended to the left-hand array; for keys that exist in both arrays, the elements from the left-hand array will be used, and the matching elements from the right-hand array will be ignored."
@DarioFumagalli Wonderful! I can't imagine how you got that result. I couldn't reproduce it in my environment. I would love to see the code you have used to produce that result. I guess you must be using some strange or old version of PHP.
@DarioFumagalli I don't know if I'm misunderstanding or if it's just changed since 2016, but at this point in time, the operation print_r([2 => 56] + [2 => 30]); yields Array ( [2] => 56 ). So, it's keeping the left hand side as specified. This is as of PHP 7.1.19, running on repl.it.
87

Considering that you have

$replaced = array('1' => 'value1', '4' => 'value4');
$replacement = array('4' => 'value2', '6' => 'value3');

Doing $merge = $replacement + $replaced; will output:

Array('4' => 'value2', '6' => 'value3', '1' => 'value1');

The first array from sum will have values in the final output.

Doing $merge = $replaced + $replacement; will output:

Array('1' => 'value1', '4' => 'value4', '6' => 'value3');

4 Comments

To sum up, when adding 2 arrays, values from the first override values from the second.
I thought the second will override the first. :)
Exactly. That's why I couldn't use $allValues += $newValues;.
Doing $merge = $replacement + $replaced; will output: Array ( [4] => value2 [6] => value3 [1] => value1 )
61

I just want to add another possibility of doing a merge while keeping keys.

Besides adding key/values to existing arrays using the + sign you could do an array_replace.

$a = array(
    'foo'  => 'bar',
    'some' => 'string',
    'me'   => 'is original'
);
$b = array(
    42   => 'answer to the life and everything',
    1337 => 'leet',
    'me' => 'is overridden'
);

$merged = array_replace($a, $b);

The result will be:

$merged = array(
    'foo'  => 'bar',
    'some' => 'string',
    'me'   => 'is overridden',
    42     => 'answer to the life and everything',
    1337   => 'leet'
);

Same keys will be overwritten by the latter array.
There is also an array_replace_recursive, which do this for subarrays, too.

Live example on 3v4l.org

Comments

4

Two arrays can be easily added or union without chaning their original indexing by + operator. This will be very help full in laravel and codeigniter select dropdown.

 $empty_option = array(
         ''=>'Select Option'
          );

 $option_list = array(
          1=>'Red',
          2=>'White',
          3=>'Green',
         );

  $arr_option = $empty_option + $option_list;

Output will be :

$arr_option = array(
   ''=>'Select Option'
   1=>'Red',
   2=>'White',
   3=>'Green',
 );

Comments

2

Try array_replace_recursive or array_replace functions

$a = array('userID' => 1, 'username'=> 2);
array (
  userID => 1,
  username => 2
)
$b = array('userID' => 1, 'companyID' => 3);
array (
  'userID' => 1,
  'companyID' => 3
)
$c = array_replace_recursive($a,$b);
array (
  userID => 1,
  username => 2,
  companyID => 3
)

http://php.net/manual/en/function.array-replace-recursive.php

Comments

2

The OP.'s requirement is to preserve keys (keep keys) and not overlap (I think overwrite). In some cases such as numeric keys it is possible but if string keys it seems to be not possible.

If you use array_merge() the numeric keys will always re-index or renumbered.

If you use array_replace(), array_replace_recursive() it will be overlap or overwrite from the right to the left. The value with the same key on first array will be replaced with second array.

If you use $array1 + $array2 as the comment was mentioned, if the keys are same then it will keep the value from first array but drop the second array.

Custom function.

Here is my function that I just wrote to work on the same requirements. You are free to use for any purpose.

/**
 * Array custom merge. Preserve indexed array key (numbers) but overwrite string key (same as PHP's `array_merge()` function).
 * 
 * If the another array key is string, it will be overwrite the first array.<br>
 * If the another array key is integer, it will be add to first array depend on duplicated key or not. 
 * If it is not duplicate key with the first, the key will be preserve and add to the first array.
 * If it is duplicated then it will be re-index the number append to the first array.
 *
 * @param array $array1 The first array is main array.
 * @param array ...$arrays The another arrays to merge with the first.
 * @return array Return merged array.
 */
function arrayCustomMerge(array $array1, array ...$arrays): array
{
    foreach ($arrays as $additionalArray) {
        foreach ($additionalArray as $key => $item) {
            if (is_string($key)) {
                // if associative array.
                // item on the right will always overwrite on the left.
                $array1[$key] = $item;
            } elseif (is_int($key) && !array_key_exists($key, $array1)) {
                // if key is number. this should be indexed array.
                // and if array 1 is not already has this key.
                // add this array with the key preserved to array 1.
                $array1[$key] = $item;
            } else {
                // if anything else...
                // get all keys from array 1 (numbers only).
                $array1Keys = array_filter(array_keys($array1), 'is_int');
                // next key index = get max array key number + 1.
                $nextKeyIndex = (intval(max($array1Keys)) + 1);
                unset($array1Keys);
                // set array with the next key index.
                $array1[$nextKeyIndex] = $item;
                unset($nextKeyIndex);
            }
        }// endforeach; $additionalArray
        unset($item, $key);
    }// endforeach;
    unset($additionalArray);

    return $array1;
}// arrayCustomMerge

Testing.

<?php
$array1 = [
    'cat', 
    'bear', 
    'fruitred' => 'apple',
    3 => 'dog',
    null => 'null',
];
$array2 = [
    1 => 'polar bear',
    20 => 'monkey',
    'fruitred' => 'strawberry',
    'fruityellow' => 'banana',
    null => 'another null',
];

// require `arrayCustomMerge()` function here.

function printDebug($message)
{
    echo '<pre>';
    print_r($message);
    echo '</pre>' . PHP_EOL;
}

echo 'array1: <br>';
printDebug($array1);
echo 'array2: <br>';
printDebug($array2);


echo PHP_EOL . '<hr>' . PHP_EOL . PHP_EOL;


echo 'arrayCustomMerge:<br>';
$merged = arrayCustomMerge($array1, $array2);
printDebug($merged);


assert($merged[0] == 'cat', 'array key 0 should be \'cat\'');
assert($merged[1] == 'bear', 'array key 1 should be \'bear\'');
assert($merged['fruitred'] == 'strawberry', 'array key \'fruitred\' should be \'strawberry\'');
assert($merged[3] == 'dog', 'array key 3 should be \'dog\'');
assert(array_search('another null', $merged) !== false, '\'another null\' should be merged.');
assert(array_search('polar bear', $merged) !== false, '\'polar bear\' should be merged.');
assert($merged[20] == 'monkey', 'array key 20 should be \'monkey\'');
assert($merged['fruityellow'] == 'banana', 'array key \'fruityellow\' should be \'banana\'');

The results.

array1:

Array
(
    [0] => cat
    [1] => bear
    [fruitred] => apple
    [3] => dog
    [] => null
)

array2:

Array
(
    [1] => polar bear
    [20] => monkey
    [fruitred] => strawberry
    [fruityellow] => banana
    [] => another null
)

---
arrayCustomMerge:

Array
(
    [0] => cat
    [1] => bear
    [fruitred] => strawberry
    [3] => dog
    [] => another null
    [4] => polar bear
    [20] => monkey
    [fruityellow] => banana
)

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.