Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I have a collection of keys in this massive flat single array I would like to basically expand that array into a multidimensional one organized by keys - here is an example:

'invoice/products/data/item1'
'invoice/products/data/item2'
'invoice/products/data/item2'

=>

'invoice'=>'products'=>array('item1','item2','item3')

how can I do this - the length of the above strings are variable...

Thanks!

share|improve this question
1  
'invoice'=>'products'=>array() is not valid syntax. Did you mean 'invoice'=>array('products'=>array())? – Lekensteyn Oct 10 '10 at 19:28
1  
is it always 3 dimensions or can it vary? – Imre L Oct 10 '10 at 19:33
What about data? Why isn’t it array('invoice'=>array('products'=>array('data'=>array('item1','item2','item3')‌​)))? – Gumbo Oct 10 '10 at 20:22
actually that's better formatting – ronaktal Oct 10 '10 at 22:52

3 Answers

up vote 2 down vote accepted

Something along these lines: (Didn't test it though!) Works now ;)

$data = array();
$current = &$data;
foreach($keys as $value) {
  $parts = explode("/", $value);
  $parts_count = count($parts);
  foreach($parts as $i => $part) {
    if(!array_key_exists($part, $current)) {
      if($i == $parts_count - 1) {
        $current[] = $part;
      }
      else {
        $current[$part] = array();
        $current = &$current[$part];
      }
    }
    else {
      $current = &$current[$part];
    }
  }
  $current = &$data;
}

$keys beeing the flat array.

share|improve this answer
congrats - works, thanks – ronaktal Oct 10 '10 at 22:45
$src = array(
'invoice/products/data/item1',
'invoice/products/data/item2',
'invoice/products/data/item2',
'foo/bar/baz',
'aaa/bbb'
);

function rsplit(&$v, $w)
{
    list($first, $tail) = explode('/', $w, 2);
    if(empty($tail)) 
    {
        $v[] = $first;
        return $v;
    }
    $v[$first] =  rsplit($v[$first], $tail);
    return $v;

}

$result = array_reduce($src, "rsplit");
print_r($result);

Output is:

Array (
    [invoice] => Array
        (
            [products] => Array
                (
                    [data] => Array
                        (
                            [0] => item1
                            [1] => item2
                            [2] => item2
                        )

                )

        )

    [foo] => Array
        (
            [bar] => Array
                (
                    [0] => baz
                )

        )

    [aaa] => Array
        (
            [0] => bbb
        )

)
share|improve this answer
This is a beautiful functional solution and deserves way, way more upvotes than it currently has. – erisco Oct 11 '10 at 4:02
i agree, awesome – ronaktal Oct 15 '10 at 12:40

Although it's not clear from your question how the "/" separated strings will map to an array, the basic approach will probably be something like this:

$result = array();
$k1 = $k2 = '';
ksort($yourData); // This is the key (!)
foreach ($yourData as $k => $v) {
  // Use if / else if / else if to watch for new sub arrays and change
  // $k1, $k2 accordingly
  $result[$k1][$k2] = $v;
}

This approach uses the ksort to ensure that keys at the same "level" appear together, like this:

'invoice/products/data1/item1'
'invoice/products/data1/item2'
'invoice/products/data2/item3'
'invoice/products2/data3/item4'
'invoice/products2/data3/item5'

Notice how the ksort corresponds to the key grouping you're aiming for.

share|improve this answer
nice, works - slightly faster – ronaktal Oct 15 '10 at 12:41

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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