As far as I understood, you need to display cities in the same order as they appear in the second array.
Try this:
$array1 = array(
'DETROIT' => array(
'NORTH' => '20.00%',
'SOUTH' => '30.00%',
'WEST' => '25.00%',
),
'CHICAGO' => array(
'NORTH' => '59.14%',
'SOUTH' => '12.94%',
'WEST' => '0.00%',
'EAST' => '34.60%',
),
'NEW YORK' => array(
'WEST' => '38.00%',
'EAST' => '49.00%',
),
'DALLAS' => array(
'WEST' => '60.57%',
),
);
$array2 = array(
'John Doe' => array(
'DETROIT',
'DALLAS',
),
'Sara Smith' => array(
'NEW YORK',
),
'Donald Duck' => array(
'CHICAGO',
),
);
function get2ndLevel($arr, $bKeys = false) {
$vals = array();
array_walk($arr, function($v, $k) use(&$vals, $bKeys){
$vals = array_merge($vals, $bKeys? array_keys($v) : array_values($v));
});
return array_values(array_unique($vals));
}
$dirs = get2ndLevel($array1, true);
$cities = get2ndLevel($array2);
$cities = array_merge($cities,
array_values(array_diff(array_keys($array1), $cities))
);
$table = "<tr><td> </td>";
foreach ($cities as $city){
$table .= "<td>" . $city . "</td>";
}
$table .= "</tr>";
foreach ($dirs as $dir){
$table .= "<tr><td>" . $dir . "</td>";
foreach ($cities as $city){
$table .= "<td>" . (isset($array1[$city][$dir])? $array1[$city][$dir] : "N/A") . "</td>";
}
$table .= "</tr>";
}
echo "<table>". $table. "</table>";
Demo