2
\$\begingroup\$

I would like to convert ($data):

Array
(
    [login] => Log in
    [logout] => Log out

    [label] => Array
        (
            [email] => [email protected] 
            [name] => Some name
        )

    [controllers] => Array
        (
            [page] => Array
                (
                    [title_new] => New page 
                    [title_edit] => Edit page
                    [submit_button] => Submit page
                )
        )
)

To ($result):

Array
(
    [login] => Log in
    [logout] => Log out
    [label[email]] => [email protected]
    [label[name]] => Some name
    [controllers[page][title_new]] => New page
    [controllers[page][title_edit]] => Edit page
    [controllers[page][submit_button]] => Submit page
 )

The following code works "fine":

$data = some_data;
$result = array();

foreach ($data as $k => $v) {
  if (is_array($v))
    foreach ($v as $_k => $_v)
      if (is_array($_v))
        foreach ($_v as $__k => $__v)
          if (is_array($__v))
            foreach ($__v as $___k => $___v)
              $result[$k.'['.$_k.']['.$__k.']['.$___k.']'] = $___v;
          else
            $result[$k.'['.$_k.']['.$__k.']'] = $__v;
      else
        $result[$k.'['.$_k.']'] = $_v;
  else
    $result[$k] = $v;
}

The code work nicely for four levels, and after that it returns "Array" as the value. I think I need recursion, but I would like for you to review my current code, and optionally present me with a solution to go even deeper.

\$\endgroup\$
0

1 Answer 1

3
\$\begingroup\$

So I probably need some kind of recursion, but I have no clue how to get around that with PHP

Recursion in PHP is the same as basically any language (well... at a very high level).

I'm very torn on if I think your question is on topic or not, but it's been a long time since I've written anything recursive, and I'm a shameless rep-whore, so here's my go:

function flatten(array $arr, $prefix = '')
{
    $out = array();
    foreach ($arr as $k => $v) {
        $key = (!strlen($prefix)) ? $k : "{$prefix}[{$k}]";
        if (is_array($v)) {
            $out += flatten($v, $key);
        } else {
            $out[$key] = $v;
        }
    }
    return $out;
}

Or, if you don't like the magical second param:

function _flatten(array &$out, array $arr, $prefix)
{
    foreach ($arr as $k => $v) {
        $key = (!strlen($prefix)) ? $k : "{$prefix}[{$k}]";
        if (is_array($v)) {
            _flatten($out, $v, $key);
        } else {
            $out[$key] = $v;
        }
    }
}

function flatten(array $arr)
{

    $flat = array();
    _flatten($flat, $arr, '');
    return $flat;

}

You could also optimize a bit and make a lot of the things in there references (the for loop values and function params). I tend to avoid references in PHP though unless I have an extremely strong reason for them. (If you plan on using this function on arrays larger than a few hundred elements, that may begin to enter into strong reason land.)

(And flatten is a horrible name, but... yeah.)

\$\endgroup\$
4
  • \$\begingroup\$ Hey, that works pretty great. Usually the arrays are indeed bigger than a few hundred elements, but not like thousands. I will try to get some benchmarks on them. Thanks! \$\endgroup\$
    – Tessmore
    Aug 15, 2012 at 10:46
  • \$\begingroup\$ Well very simple tests do show that $key = $prefix ? $k : "{$prefix}[{$k}]"; is a lot faster then the !strlen() check. Why do you use that? Other than that it looks fast enough to me. \$\endgroup\$
    – Tessmore
    Aug 15, 2012 at 11:00
  • 1
    \$\begingroup\$ @Tessmore Because 0 is a valid key and considered false. I suppose a faster version than strlen could be ((string) $prefix) !== ''). Or, the fastest would probably actually be to have $prefix default to null and just check $prefix === null. \$\endgroup\$
    – Corbin
    Aug 15, 2012 at 11:02
  • \$\begingroup\$ Ye I did the last one \$\endgroup\$
    – Tessmore
    Aug 15, 2012 at 11:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.