5

Let's say, I have an array like this:

$array = [
    'car' => [
        'BMW' => 'blue',
        'toyota' => 'gray'
        ],
    'animal' => [
        'cat' => 'orange',
        'horse' => 'white'
        ]
    ];

Then, I want to get all the values (the colour, 'blue', 'gray', 'orange', 'white') and join them into a single array. How do I do that without using foreach twice?

Thanks in advance.

Jonny Henly
  • 4,023
  • 4
  • 26
  • 43
Vaivez66
  • 63
  • 1
  • 1
  • 5
  • Write a function that uses `for-each` twice, then just call that function. – Jonny Henly Jun 29 '16 at 02:45
  • I have, but won't that affect to the performance every time I call it? – Vaivez66 Jun 29 '16 at 02:47
  • I'm not incredibly familiar with PHP, so I don't know if there is a built-in function that can achieve what you want and doesn't use nested for loops. I wouldn't worry about iterating over two arrays unless it's actually noticeable. Premature optimization is the root of all evil. – Jonny Henly Jun 29 '16 at 02:50
  • Okay... To be honest, I'm not familiar either... – Vaivez66 Jun 29 '16 at 02:51
  • SPL Recursive Iterator http://php.net/manual/en/class.recursivearrayiterator.php SEE: http://stackoverflow.com/questions/1319903/how-to-flatten-a-multidimensional-array – ArtisticPhoenix Jun 29 '16 at 02:53
  • Another option is to flatten the original array. In this case the objects are very dissimilar, but if both objects were cars for example: $array = [ 'car_BMW' => 'blue', 'car_toyota' =>'gray' ]; – WSimpson Jun 29 '16 at 03:42

7 Answers7

7

TL;DR

$result = call_user_func_array('array_merge', $array);

Credit: How to "flatten" a multi-dimensional array to simple one in PHP?

In your use case, you should use it like this:

<?php
$array = [
    'car' => [
        'BMW' => 'blue',
        'toyota' => 'gray'
        ],
    'animal' => [
        'cat' => 'orange',
        'horse' => 'white'
        ]
    ];
$result = call_user_func_array('array_merge', $array);
$result = array_values($result);

//$result = ['blue', 'gray', 'orange', 'white']
Community
  • 1
  • 1
Ng Sek Long
  • 4,233
  • 2
  • 31
  • 38
  • This is interesting, but does not get all values. I mean it only get 2nd level values. So not even 1st level (if there are any). – cottton Apr 05 '21 at 17:21
  • @cottton was a bit late on the response, but yes this solution only works if you are getting 2nd level values. I suggest you just use a for loop if you are going both 1st and 2nd level value, since it probably is too complex for any one-liner, cheers! – Ng Sek Long Nov 16 '21 at 03:30
  • if you face error `array_merge() does not accept unknown named parameters` on PHP8 check this answer https://stackoverflow.com/q/69424097/4896948 – Nuryagdy Mustapayev Aug 19 '22 at 13:26
3

Old but as far i see not really a "working on all cases" function posted.

So here is the common classic recursively function:

function getArrayValuesRecursively(array $array)
{
    $values = [];
    foreach ($array as $value) {
        if (is_array($value)) {
            $values = array_merge($values,
                getArrayValuesRecursively($value));
        } else {
            $values[] = $value;
        }
    }
    return $values;
}

Example array:

$array = [
    'car'    => [
        'BMW'    => 'blue',
        'toyota' => 'gray'
    ],
    'animal' => [
        'cat'   => 'orange',
        'horse' => 'white'
    ],
    'foo'    => [
        'bar',
        'baz' => [
            1,
            2 => [
                2.1,
                'deep' => [
                    'red'
                ],
                2.2,
            ],
            3,
        ]
    ],
];

Call:

echo var_export(getArrayValuesRecursively($array), true) . PHP_EOL;

Result:

// array(
//     0 => 'blue',
//     1 => 'gray',
//     2 => 'orange',
//     3 => 'white',
//     4 => 'bar',
//     5 => 1,
//     6 => 2.1,
//     7 => 'red',
//     8 => 2.2,
//     9 => 3,
// )
cottton
  • 1,522
  • 14
  • 29
1

Try this:

function get_values($array){
    foreach($array as $key => $value){
        if(is_array($array[$key])){
            print_r (array_values($array[$key]));
        }
    }
}

get_values($array);
André Senra
  • 1,875
  • 2
  • 11
  • 13
1

How do I do that without using foreach twice?

First use RecursiveIteratorIterator class to flatten the multidimensional array, and then apply array_values() function to get the desired color values in a single array.

Here are the references:

So your code should be like this:

$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($array));
$flatten_array = array_values(iterator_to_array($iterator,true));

// display $flatten_array
echo "<pre>"; print_r($flatten_array);

Here's the live demo

Rajdeep Paul
  • 16,887
  • 3
  • 18
  • 37
  • Interesting, but does not work with "mixed" arrays. As soon you got in one array a values and another array the method is "ignoring" the value in that one. Example array: `['foo' => ['bar', 'baz' => [1, 2, 3]]]` – cottton Apr 05 '21 at 17:25
1

Here's a recursive function that gives you both the ability to get an array of those endpoint values, or to get an array with all keys intact, but just flattened.

Code:

<?php

$array = [
    'car' => [
        'BMW' => 'blue',
        'toyota' => 'gray'
        ],
    'animal' => [
        'cat' => 'orange',
        'horse' => 'white'
        ]
    ];

//
print "\n<br> Array (Original): ".print_r($array,true);
print "\n<br> Array (Flattened, With Keys): ".print_r(FlattenMultiArray($array,true),true);
print "\n<br> Array (Flattened, No Keys): ".print_r(FlattenMultiArray($array,false),true);

//
function FlattenMultiArray($array,$bKeepKeys=true,$key_prefix='')
{
    //
    $array_flattened=Array();

    //
    foreach($array as $key=>$value){

        //
        if(Is_Array($value)){
            $array_flattened=Array_Merge(
                $array_flattened,
                FlattenMultiArray($value,$bKeepKeys,$key)
            );
        }
        else{
            if($bKeepKeys){
                $array_flattened["{$key_prefix}_{$key}"]=$value;
            }
            else{
                $array_flattened[]=$value;
            }
        }
    }

    return $array_flattened;
}

?>

Outputs:

<br> Array (Original): Array
(
    [car] => Array
        (
            [BMW] => blue
            [toyota] => gray
        )

    [animal] => Array
        (
            [cat] => orange
            [horse] => white
        )

)

<br> Array (Flattened, With Keys): Array
(
    [car_BMW] => blue
    [car_toyota] => gray
    [animal_cat] => orange
    [animal_horse] => white
)

<br> Array (Flattened, No Keys): Array
(
    [0] => blue
    [1] => gray
    [2] => orange
    [3] => white
)
omghai_8782
  • 468
  • 4
  • 11
0

If you don't care about the indexes, then this should do it:

$colors = array();
foreach ($array as $item) {
  $colors = array_merge($colors, array_values($item));
}

If you want to keep the indexes you could use:

$colors = array();
foreach ($array as $item) {
  // this leaves you open to elements overwriting each other depending on their keys
  $colors = array_merge($colors, $item);
}

I hope this helps.

Kirito
  • 307
  • 2
  • 7
0

what about this one?It works with ANY array depth.

private function flattenMultiArray($array)
{
    $result = [];
    self::flattenKeyRecursively($array, $result, '');

    return $result;
}

private static function flattenKeyRecursively($array, &$result, $parentKey)
{
    foreach ($array as $key => $value) {
        $itemKey = ($parentKey ? $parentKey . '.' : '') . $key;
        if (is_array($value)) {
            self::flattenKeyRecursively($value, $result, $itemKey);
        } else {
            $result[$itemKey] = $value;
        }
    }
}

P.S. solution is not mine, but works perfectly, and I hope it will help someone. Original source:

https://github.com/letsdrink/ouzo/blob/master/src/Ouzo/Goodies/Utilities/Arrays.php

Deadpool
  • 735
  • 8
  • 15