PHP - How to merge arrays inside array

PhpArray Merge

Php Problem Overview


How to merge n number of array in php. I mean how can I do the job like :
array_merge(from : $result[0], to : $result[count($result)-1])
OR
array_merge_recursive(from: $result[0], to : $result[count($result) -1])


Where $result is an array with multiple arrays inside it like this :

$result = Array(
0 => array(),//associative array
1 => array(),//associative array
2 => array(),//associative array
3 => array()//associative array
)

My Result is :

$result = Array(
	0 => Array(
		"name" => "Name",
		"events" => 1,
		"types" => 2
	),
	1 => Array(
		"name" => "Name",
		"events" => 1,
		"types" => 3
	),
	2 => Array(
		"name" => "Name",
		"events" => 1,
		"types" => 4
	),
	3 => Array(
		"name" => "Name",
		"events" => 2,
		"types" => 2
	),
	4 => Array(
		"name" => "Name",
		"events" => 3,
		"types" => 2
	)
)

And what I need is

$result = Array(
"name" => "name",
"events" => array(1,2,3),
"types" => array(2,3,4)
)

Php Solutions


Solution 1 - Php

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.

Solution 2 - Php

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
)

Solution 3 - Php

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 https://stackoverflow.com/questions/5929642/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
)

Solution 4 - Php

Try this

$result = array_merge($array1, $array2);

Or, instead of array_merge, you can use the + op which performs a union:

$array2 + array_fill_keys($array1, '');

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionLekhnathView Question on Stackoverflow
Solution 1 - Phpcomplex857View Answer on Stackoverflow
Solution 2 - PhpamurrellView Answer on Stackoverflow
Solution 3 - PhpFriedrichView Answer on Stackoverflow
Solution 4 - PhpJayramView Answer on Stackoverflow