PHP - How to merge arrays inside array
array_merge can take variable number of arguments, so with a little call_user_func_array trickery you can pass your $result
array to it:
$merged = call_user_func_array('array_merge', $result);
This basically run like if you would have typed:
$merged = array_merge($result[0], $result[1], .... $result[n]);
Update:
Now with 5.6, we have the ...
operator to unpack arrays to arguments, so you can:
$merged = array_merge(...$result);
And have the same results. *
* The same results as long you have integer keys in the unpacked array, otherwise you'll get an E_RECOVERABLE_ERROR : type 4096 -- Cannot unpack array with string keys
error.
If you would like to:
- check that each param going into array_merge is actually an array
- specify a particular property within one of the arrays to merge by
You can use this function:
function mergeArrayofArrays($array, $property = null){ return array_reduce( (array) $array, // make sure this is an array too, or array_reduce is mad. function($carry, $item) use ($property) { $mergeOnProperty = (!$property) ? $item : (is_array($item) ? $item[$property] : $item->$property); return is_array($mergeOnProperty) ? array_merge($carry, $mergeOnProperty) : $carry; }, array()); // start the carry with empty array}
Let's see it in action.. here's some data:
Simple structure: Pure array of arrays to merge.
$peopleByTypesSimple = [ 'teachers' => [ 0 => (object) ['name' => 'Ms. Jo', 'hair_color' => 'brown'], 1 => (object) ['name' => 'Mr. Bob', 'hair_color' => 'red'], ], 'students' => [ 0 => (object) ['name' => 'Joey', 'hair_color' => 'blonde'], 1 => (object) ['name' => 'Anna', 'hair_color' => 'Strawberry Blonde'], ], 'parents' => [ 0 => (object) ['name' => 'Mr. Howard', 'hair_color' => 'black'], 1 => (object) ['name' => 'Ms. Wendle', 'hair_color' => 'Auburn'], ],];
Less simple: Array of arrays, but would like to specify the people and ignore the count.
$peopleByTypes = [ 'teachers' => [ 'count' => 2, 'people' => [ 0 => (object) ['name' => 'Ms. Jo', 'hair_color' => 'brown'], 1 => (object) ['name' => 'Mr. Bob', 'hair_color' => 'red'], ] ], 'students' => [ 'count' => 2, 'people' => [ 0 => (object) ['name' => 'Joey', 'hair_color' => 'blonde'], 1 => (object) ['name' => 'Anna', 'hair_color' => 'Strawberry Blonde'], ] ], 'parents' => [ 'count' => 2, 'people' => [ 0 => (object) ['name' => 'Mr. Howard', 'hair_color' => 'black'], 1 => (object) ['name' => 'Ms. Wendle', 'hair_color' => 'Auburn'], ] ],];
Run it
$peopleSimple = mergeArrayofArrays($peopleByTypesSimple);$people = mergeArrayofArrays($peopleByTypes, 'people');
Results - Both return this:
Array( [0] => stdClass Object ( [name] => Ms. Jo [hair_color] => brown ) [1] => stdClass Object ( [name] => Mr. Bob [hair_color] => red ) [2] => stdClass Object ( [name] => Joey [hair_color] => blonde ) [3] => stdClass Object ( [name] => Anna [hair_color] => Strawberry Blonde ) [4] => stdClass Object ( [name] => Mr. Howard [hair_color] => black ) [5] => stdClass Object ( [name] => Ms. Wendle [hair_color] => Auburn ))
Extra Fun: If you want to single out one property in an array or object, like "name" from an array of people objects(or associate arrays), you can use this function
function getSinglePropFromCollection($propName, $collection, $getter = true){ return (empty($collection)) ? [] : array_map(function($item) use ($propName) { return is_array($item) ? $item[$propName] : ($getter) ? $item->{'get' . ucwords($propName)}() : $item->{$propName} }, $collection);}
The getter is for possibly protected/private objects.
$namesOnly = getSinglePropFromCollection('name', $peopleResults, false);
returns
Array( [0] => Ms. Jo [1] => Mr. Bob [2] => Joey [3] => Anna [4] => Mr. Howard [5] => Ms. Wendle)
I really liked the answer from complex857 but it didn't work for me, because I had numeric keys in my arrays that I needed to preserve.
I used the +
operator to preserve the keys (as suggested in PHP array_merge with numerical keys) and used array_reduce
to merge the array.
So if you want to merge arrays inside an array while preserving numerical keys you can do it as follows:
<?php$a = [ [0 => 'Test 1'], [0 => 'Test 2', 2 => 'foo'], [1 => 'Bar'],]; print_r(array_reduce($a, function ($carry, $item) { return $carry + $item; }, []));?>
Result:
Array( [0] => Test 1 [2] => foo [1] => Bar)