5

Is there any fast way to flatten an array and select subkeys ('key'&'value' in this case) without running a foreach loop, or is the foreach always the fastest way?

Array
(
    [0] => Array
        (
            [key] => string
            [value] => a simple string
            [cas] => 0
        )

    [1] => Array
        (
            [key] => int
            [value] => 99
            [cas] => 0
        )

    [2] => Array
        (
            [key] => array
            [value] => Array
                (
                    [0] => 11
                    [1] => 12
                )

            [cas] => 0
        )

)

To:

Array
(
    [int] => 99
    [string] => a simple string
    [array] => Array
        (
            [0] => 11
            [1] => 12
        )
)
Your Common Sense
  • 156,878
  • 40
  • 214
  • 345
Industrial
  • 41,400
  • 69
  • 194
  • 289

4 Answers4

3

Give this a shot:

$ret = array();
while ($el = each($array)) {
    $ret[$el['value']['key']] = $el['value']['value'];
}
ircmaxell
  • 163,128
  • 34
  • 264
  • 314
  • 1
    oh what an ancient operators :) – Your Common Sense May 28 '10 at 17:01
  • I would recomend always initializing the array iterator using `reset($array)` just before iterating that way, to avoid that another call to, e.g. `end()` would have messed with it. Lots of ways to fall for that trap... – Gui Prá Feb 18 '13 at 17:29
3

call_user_func_array("array_merge", $subarrays) can be used to "flatten" nested arrays.
What you want is something entirely different. You could use array_walk() with a callback instead to extract the data into the desired format. But no, the foreach loop is still faster. There's no array_* method to achieve your structure otherwise.

VisioN
  • 143,310
  • 32
  • 282
  • 281
mario
  • 144,265
  • 20
  • 237
  • 291
  • array_walk wouldn't work in itself, because it doesn't return anything except a bool (and you can't modify the key of the array). – ircmaxell May 28 '10 at 17:04
0

Hopefully it will help someone else, but here is a function I use to flatten arrays and make nested elements more accessible.

Usage and description here: https://totaldev.com/flatten-multidimensional-arrays-php/

The function:

// Flatten an array of data with full-path string keys
function flat($array, $separator = '|', $prefix = '', $flattenNumericKeys = false) {
    $result = [];

    foreach($array as $key => $value) {
        $new_key = $prefix . (empty($prefix) ? '' : $separator) . $key;

        // Make sure value isn't empty
        if(is_array($value)) {
            if(empty($value)) $value = null;
            else if(count($value) == 1 && isset($value[0]) && is_string($value[0]) && empty(trim($value[0]))) $value = null;
        }

        $hasStringKeys = is_array($value) && count(array_filter(array_keys($value), 'is_string')) > 0;
        if(is_array($value) && ($hasStringKeys || $flattenNumericKeys)) $result = array_merge($result, flat($value, $separator, $new_key, $flattenNumericKeys));
        else $result[$new_key] = $value;
    }

    return $result;
}
matt
  • 670
  • 2
  • 9
  • 18
-1

This should properly combine arrays with integer keys. If the keys are contiguous and start at zero, they will be dropped. If an integer key doesn't yet exist in the flat array, it will be kept as-is; this should mostly preserve non-contiguous arrays.

function array_flatten(/* ... */)
{
    $flat = array();
    array_walk_recursive(func_get_args(), function($value, $key)
    {
        if (array_key_exists($key, $flat))
        {
            if (is_int($key))
            {
                $flat[] = $value;
            }
        }
        else
        {
            $flat[$key] = $value;
        }
    });
    return $flat;
}

You could use !isset($key) or empty($key) instead to favor useful values.

Here's a more concise version:

function array_flatten(/* ... */)
{
    $flat = array();
    array_walk_recursive(func_get_args(), function($value, $key) use (&$flat)
    {
        $flat = array_merge($flat, array($key => $value));
    });
    return $flat;
}
Zenexer
  • 18,788
  • 9
  • 71
  • 77