Search code examples
phparraysmultidimensional-arraygroupinghierarchical-data

Restructure 2d query result into a multidimensional hierarchial associative array


I am developing a CodeIgniter application and I need to restructure a query result coming from a model method so produce a multi-level, hierarchial associative array.

My model provides the following payload:

$array = [
    ['id' => 1, 'category' => 'Pizza', 'product' => 'Large Pizza', 'complement_type' => 'Bread', 'option' => 'Brown bread'],
    ['id' => 2, 'category' => 'Pizza', 'product' => 'Small Pizza', 'complement_type' => 'Bread', 'option' => 'White bread'],
    ['id' => 3, 'category' => 'Pizza', 'product' => 'Small Pizza', 'complement_type' => 'Ingredients', 'option' => 'Olives'],          
    ['id' => 4, 'category' => 'Salads', 'product' => 'Green Salad', 'complement_type' => 'Extras', 'option' => 'Bacon'],
    ['id' => 5, 'category' => 'Salads', 'product' => 'Cesars Salad', 'complement_type' => 'Extras', 'option' => 'Lettuce'],
];

I need to nest the data in a particular order:

category -> product -> complement_type = option

My desired structure:

array (
  'Pizza' => 
  array (
    'Large Pizza' => 
    array (
      'Bread' => 'Brown bread',
    ),
    'Small Pizza' => 
    array (
      'Bread' => 'White bread',
      'Ingredients' => 'Olives',
    ),
  ),
  'Salads' => 
  array (
    'Green Salad' => 
    array (
      'Extras' => 'Bacon',
    ),
    'Cesars Salad' => 
    array (
      'Extras' => 'Lettuce',
    ),
  ),
)

I think I have to loop it with a for() loop, maybe add a while() loop to get the changes in the categories, but I just can't seem to find the way to do it.


Solution

  • First of all: your original array — as posted is comment — if an array of objects: this preliminar note is to understand the syntax ->, otherwise obscure simply reading your main question.

    Assuming your table results are stored in array $array, you can try in this way:

    $result = array();
    foreach( $array as $row )
    {
        if( !isset( $result[ $row->category ] ) ) 
        {
            $result[ $row->category ] = array();
        }
        if( !isset( $result[ $row->category ][ $row->product ] ) )
        {
            $result[ $row->category ][ $row->product ] = array();
        }
        $result[ $row->category ][ $row->product ][ $row->complement_type ] = $row->option;
    }
    

    At beginning, I init an empty array. Then — through a foreach loop, I process each element of $array and — if primary key (the product) doesn't exist in the result array, I create it as empty array; then I perform same action for category subkey (Large Pizza, etc). At last, I add the complement type.

    3v4l.org demo