2
\$\begingroup\$

I would like to convert ($data):

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

    [label] => Array
        (
            [email] => test@test.com 
            [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]] => test@test.com
    [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\$
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\$
  • \$\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 '12 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 '12 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 '12 at 11:02
  • \$\begingroup\$ Ye I did the last one \$\endgroup\$ – Tessmore Aug 15 '12 at 11:03

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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