uncovery uncovery - 3 months ago 12
PHP Question

Creating a dynamic hierarchical array in PHP

I have this general data structure:

$levels = array('country', 'state', 'city', 'location');


I have data that looks like this:

$locations = array(
1 => array('country'=>'USA', 'state'=>'New York', 'city'=>'NYC', 'location'=>'Central Park', 'count'=>123),
2 => array('country'=>'Germany', ... )
);


I want to create hierarchical arrays such as

$hierarchy = array(
'USA' => array(
'New York' => array(
'NYC' => array(
'Central Park' => 123,
),
),
),
'Germany' => array(...),
);


Generally I would just create it like this:

$final = array();
foreach ($locations as $L) {
$final[$L['country']][$L['state']][$L['city']][$L['location']] = $L['count'];
}


However, it turns out that the initial array $levels is dynamic and can change in values and length So I cannot hard-code the levels into that last line, and I do not know how many elements there are. So the $levels array might look like this:

$levels = array('country', 'state');


Or

$levels = array('country', 'state', 'location');


The values will always exist in the data to be processed, but there might be more elements in the processed data than in the levels array. I want the final array to only contain the values that are in the $levels array, no matter what additional values are in the original data.

How can I use the array $levels as a guidance to dynamically create the $final array?

I thought I could just build the string
$final[$L['country']][$L['state']][$L['city']][$L['location']]
with implode() and then run eval() on it, but is there are a better way?

Answer

Here's my implementation. You can try it out here:

$locations = array(
  1 => array('country'=>'USA', 'state'=>'New York', 'city'=>'NYC', 'location'=>'Central Park', 'count'=>123),
  2 => array('country'=>'Germany', 'state'=>'Blah', 'city'=>'NY', 'location'=>'Testing', 'count'=>54),
);

$hierarchy = array();

$levels = array_reverse(
    array('country', 'state', 'city', 'location')
);

$lastLevel = 'count';


foreach ( $locations as $L )
{
    $array = $L[$lastLevel];

    foreach ( $levels as $level )
    {
        $array = array($L[$level] => $array);
    }

    $hierarchy = array_merge_recursive($hierarchy, $array);
}

print_r($hierarchy);
Comments