kmfk
kmfk

Reputation: 3961

Convert associative array to multidimensional array with value

This is an interesting situation which I created a working function for, but wondering if I just anyone had any simpler methods for this.

I have the following multidimensional array:

$foo = array(
    [0] => array(
        'keys' => array( 
            'key1' => 1,
            'key2' => a,
            'key3' => 123
        ),
       'values' => array(
            //goodies in here
        )
    )
    [1] => array(
        'keys' => array( 
            'key1' => 1,
            'key2' => b,
            'key3' => 456
        ),
       'values' => array(
            //goodies in here
        )
    )
)

What I wanted, was to transform this into a multidimensional array nested based on the values from the keys array, the output I was looking for is:

$bar = array(
    [1] => array(
        [a] => array(
            [123] => array( //values array from above )
        ),
        [b] => array(
            [456] => array( //values array from above )
        )
    )
)

The keys can always be nested based on their position in the keys array, but the keys themselve are not always the same, keys handles a user defined grouping, so the order and values can change. I also didn't want duplicate keys.

array_merge failed me because in a lot of cases, the array keys are actually numeric ids. So, this function works - but I'm wondering if I made myself a new pair of gloves.

   protected function convertAssociativeToMulti( &$output, $keys, $value )
   {
      $temp = array();
      $v = array_values( $keys );
      $s = sizeof( $v );
      for( $x = 0; $x < $s; $x++ )
      {
         $k = $v[ $x ];
         if ( $x == 0 )
         {
            if ( !array_key_exists( $k, $output ) )
               $output[ $k ] = array();
            $temp =& $output[ $k ];
         }
         if ( $x && ( $x + 1 ) !== $s )
         {
            if( !array_key_exists( $k, $temp ) )
               $temp[ $k ] = array();
            $temp =& $temp[$k];
         }
         if ( ( $x + 1 ) == $s )
            $temp[$k] = $value;
      }
   }

   $baz = array();
   foreach( $foo as $bar )
   {
      $this->convertAssociativeToMulti( $baz, $bar['keys'], $bar['values'] );
   }

So, how do you do this more simply / refactor what I have?

Upvotes: 6

Views: 3754

Answers (1)

Jon Hulka
Jon Hulka

Reputation: 1319

This is a bit more concise:

$result = [];
foreach($foo as $item)
{
    //Start at the outermost level of the result array
    $level = &$result;
    foreach($item['keys'] as $key)
    {
        //Add levels to the result array as needed
        if(!isset($level[$key])) $level[$key] = [];
        //Iterate to the next nested level
        $level = &$level[$key];
    }
    //Append values to the innermost level
    foreach($item['values'] as $k => $v) $level[$k] = $v;
}
//Don't keep a reference hanging around
unset($level);
var_dump($result);

Upvotes: 3

Related Questions