6

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?

4
  • 1
    +1 for the link about The Complicator's Gloves! Commented Jan 25, 2013 at 2:13
  • Take a look at my answer in this question, I think they're similar. Commented Jan 25, 2013 at 2:30
  • @Barmar - similar. I think that solution lacks maintaining the proper hierarchy for my use case. Since I loop over multiple keys arrays, they all get nested below the last set with your code. Commented Jan 25, 2013 at 2:47
  • Yeah, that explains why my code is so much shorter. It's just dealing with one entry, not an array like yours. Commented Jan 25, 2013 at 2:48

1 Answer 1

3

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);
Sign up to request clarification or add additional context in comments.

5 Comments

interesting. tried array_merge earlier because I assumed it would simplify this a lot. thought I ran into an issue of numeric keys being changed... per the docs: Values in the input array with numeric keys will be renumbered with incrementing keys starting from zero in the result array.
nevermind, I get it. thanks, tested it with my code. Had to drop the array_merge anyway, my example showed values being array, its actually an object - either way, much more concise.
Oops, I forgot about the array_merge. It's a simple foreach to replace it anyway.
actually, your array_merge was fine based on the info I gave in the question, because you were just merging values into the empty array. when I tried it earlier, I was actually trying to merge similar keys. thanks again
@mickmackusa I added some comments that hopefully clarify what is going on. It took me a while to work it out for myself - I wrote this answer 10 years ago.

Your Answer

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

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.