views:

31

answers:

3

Hi,

I'm trying to create a multidimensional array from a string (received from $_GET, input is validated, but not in this example). Each '-' will indicate a level in the multidimensional array.

Values can look like this (any form really, as long as '-' is present between keys). The array of values can map to any depth in the multidimensional array.

$array = array(
  'page-title' => 'Title of a page',
  'page-url' => 'http://www.mypage.com',
  'meta-page-author' => 'Some guy',
  'meta-page-created' => 'some timestamp'
);

I've tried different solutions, but the only thing working until now is the inital loop and extract of keys.

foreach ($array as $key => $value) {
  if (strpos($key, '-') !== false) {
    $keyArray = explode('-', $key);
    // ??
  }
}

The output I'm hoping for, should look like this:

array(
  'page' => array(
      'title' => 'Title of a page',
      'url' => 'http://www.mypage.com'
  ),
  'meta' => array(
      'page' => array(
         'author' => 'Some guy',
         'created' => 'some timestamp'
       )
  )
);
+1  A: 

Just so you're aware, PHP can be made to accept whole big arrays like that. If you name the form elements like 'somename[page][title]', then when the form returns, you should see them already arranged as an array in $_GET.

In case you have your heart set on the current naming scheme, though...

$result = array();

foreach ($array as $key => $value) {
    $current =& $result;
    if (strpos($key, '-') !== false) {
        $keyArray = explode('-', $key);
        $bottomKey = array_pop($keyArray);
        foreach ($keyArray as $subKey) {
            if (!isset($current[$subKey]))
                $current[$subKey] = array();
            $current =& $current[$subKey];
        }
    } else {
        $bottomKey = $key;
    }

    $current[$bottomKey] = $value;
}
cHao
+2  A: 

Something like this should work:

<?php
$array = array(
  'page-title' => 'Title of a page',
  'page-url' => 'http://www.mypage.com',
  'meta-page-author' => 'Some guy',
  'meta-page-created' => 'some timestamp'
);

$result = array();

foreach ($array as $key => $value) {
    $keys = strpos($key, '-') !== false ? explode('-', $key) : array($key);
    $ptr = &$result;
    foreach ($keys as $k) {
        if (!isset($ptr[$k])) {
            $ptr[$k] = array();
        }
        $ptr = &$ptr[$k];
    }
    if (empty($ptr)) {
        $ptr = $value;
    } else {
        $ptr[] = $value;
    }
}

print_r($result);

What I did was explode your keys just like you were doing. I then looped through them creating a new array if the array didn't already exist. Using a reference I save the current point I was at in the array. Then once I had hit the last key I assigned the value. Hope this helps.

EDIT: Based on cHao's recommendation I changed

$keys = strpos($key, '-') !== false ? explode('-', $key) : $key;

to

$keys = strpos($key, '-') !== false ? explode('-', $key) : array($key);

to prevent failure on the foreach.

EDIT 2: I changed

$ptr = $value;

to

if (empty($ptr)) {
    $ptr = $value;
} else {
    $ptr[] = $value;
}

to handle cases like:

$array = array(
  'page-title' => 'Title of a page',
  'page-url' => 'http://www.mypage.com',
  'meta-page-author' => 'Some guy',
  'meta-page-created' => 'some timestamp',
  'page' => 'foo'
);
blcArmadillo
very nice! i had the same thing. Afraid you beat me to the punch. No sense in posting my solution now... ;) Anyways gj
Stephen
I'm thinking the `$keys =` line, at the end, `: $key;` should be `: array($key);`. That way both branches of the ?: return an array.
cHao
Worked like a charm, thanks :)
Mads Jensen
A: 
<?php
$array = array(
  'page-title' => 'Title of a page',
  'page-url' => 'http://www.mypage.com',
  'meta-page-author' => 'Some guy',
  'meta-page-created' => 'some timestamp'
);
$result = array();
foreach ($array as $key => $value) {
    if (strpos($key, '-') !== false) {
        $ak = "result['" . str_replace('-', '\'][\'', $key) . "'] = \"".$value."\"";
        eval('$'.$ak.';');
    }
}
var_dump($result);
?>

hope that helps

harpax