Reputation: 929
I have searched for some time but I haven't found a good solution to this. There are similar posts for dealing with 1,2,3 level arrays but none that allows for an unknown level of arrays.
Aim: Cycle through x levels of multi dimensional arrays: if 1. value is array, continue cycle 2. is not an array close off cycle and output as a readable table.
I can do this manually by embedding foreach loops but whenever I try to build into a recursive function it melts.
Flat foreach example (which works for the array shown).
function doit($ARR){
if( is_array($ARR) )
{
foreach($ARR as $K => $ARR2)
{
if( is_array($ARR2) )
{
$t .= '<tr><td> > '.key($ARR).'</td>';
foreach($ARR2 as $K2 => $ARR3)
{
if( is_array($ARR3) )
{
$t .= '</tr><tr><td> >> '.key($ARR2).'</td>';
foreach($ARR3 as $K3 => $ARR4)
{
if( is_array($ARR4) )
{
$t .= '</tr><tr><td> >>> '.key($ARR3).'</td>';
foreach($ARR4 as $K4 => $ARR5)
{
if( is_array($ARR5) )
{
$t .= '</tr><tr><td> >>>> '.key($ARR4).'</td>';
foreach($ARR5 as $K5 => $ARR6)
{
if( is_array($ARR6) )
{
$t .= '</tr><tr><td> >>>>> '.key($ARR5).'</td>';
foreach($ARR6 as $K6 => $ARR7)
{
if( is_array($ARR7) )
{
$t .= '</tr><tr><td> >>>>>> '.key($ARR6).'</td>';
foreach($ARR7 as $K7 => $ARR8)
{
if( is_array($ARR8) )
{
$t .= '</tr><tr><td> >>>>>>> '.key($ARR7).'</td>';
}
else
{
$t .= '<td>'.$ARR8.'</td>';
}
}
}
else
{
$t .= '<td>'.$ARR7.'</td>';
}
}
}
else
{
$t .= '<td>'.$ARR6.'</td>';
}
}
}
else
{
$t .= '<td>'.$ARR5.'</td>';
}
}
}
else
{
$t .= '<td>'.$ARR4.'</td>';
}
}
}
else
{
$t .= '<td>'.$ARR3.'</td>';
}
}
}
else
{
$t .= '<td>'.$ARR2.'</td>';
}
}
}
else
{
}
$t .= '</tr>';
return '<table>'.$t.'</table>';
}
Example array to populate:
$IRS_EX_COVERAGE = array(
'Taxable returns:' => array(
'Individual income tax returns, total' => array(
'Returns with total positive income under $200,000 :' => array(
'Nonbusiness returns without Earned Income Tax Credit:' => array(
'Without Schedules C, E, F, or Form 2106' => array(79643929,262610,0.3,32922,229688),
'With Schedule E or Form 2106' => array(15997590,107300,0.7,49408,57892)
),
'Business returns without Earned Income Tax Credit:' => array(
'Nonfarm business returns by size of total gross receipts :' => array(
'Under $25,000' => array(10534942,94952,0.9,35192,59760),
'$25,000 under $100,000' => array(3124877,74825,2.4,24012,50813),
'$100,000 under $200,000' => array(877851,21724,2.5,13681,8043),
'$200,000 or more' => array(685163,13684,2.0,11549,2135)
),
'Farm returns' => array(1268251,4255,0.3,2475,1780)
),
'Business and nonbusiness returns with Earned Income' => array(
'Tax Credit by size of total gross receipts :' => array(
'Under $25,000' => array(6502703,459920,1.7,27009,432911),
'$25,000 or more' => array(1806228,18112,1.0,11161,6951)
)
)
),
'Returns with total positive income of at least $200,000 and under $1,000,000 :' => array(
'Nonbusiness returns' => array(4068298,71280,1.8,20795,50485),
'Business returns' => array(1734110,51151,2.9,17822,33329)
),
'Returns with total positive income of $1,000,000 or more' => array(416178,39753,9.6,13781,25972),
'International returns' => array(201097,8551,4.3,7269,1282),
)
)
);
$PRN_IRS = doit($IRS_EX_COVERAGE);
An example of the output table is shown here: http://taxformcalculator.com/IRS-audit-calculator.html
Upvotes: 1
Views: 132
Reputation: 929
Thank you malms, that was perfect. I came so close to that solution several times but kept tripping myself up.
For other who may find this, here is the final solution I used.
Note that what I wanted was to apply scaled shading via css and put leading symbols ahead of each table header subset. As malms correctly pointed out all the header should be different (see $25k question from malms).
This is how I ended up:
function doit_recurse($cellname, $arr, $maxdepth = 0, $depth = 0, $caption ) {
$ret = "";
if ($depth === 0) {
$ret .= "<table class=\"tableData\"><caption>$caption</caption>";
}
$sym = array('', '','▶','▷','▻','▹','∙');
$close_tr = "";
$tddata = "";
$tdspan = 0;
$thclass = "";
if (!empty($cellname)) {
$thclass = "class=\"nTH$depth\"";
$tdcontent = $sym[$depth]." ".$cellname." ".$depth;
$close_tr = "</tr>";
}
foreach ($arr as $key => $value) {
if (is_numeric($value)) {
$tddata .= "<td>$value</td>";
} else {
$tdspan = $maxdepth;
$tddata .= $close_tr . doit_recurse($key, $value, $maxdepth, $depth + 1);
}
}
$ret .= "<tr><th $thclass colspan=\"$tdspan\">$tdcontent</th>$tddata";
if ($depth === 0) {
$ret .= "</tr></table>";
}
return $ret;
}
$PRN_IRS = doit_recurse('', $IRS_EX_COVERAGE, 6, 0, 'Caption name here');
As you will see I also added in a caption for the table.
I wanted this approach so that I can build the html table and also build JavaScript arrays for dynamic select options (not shown but obvious how to build).
Live example here for those who are looking for anything similar. Thank again malms, that was awesome. I had really gone down the rabbit hole on that one :)
Upvotes: 0
Reputation: 153
Im not sure why your code reuses the "under 25000" text for the next entries on the same level, even if they have a different key. Here is a recursive function you can use as a starting point.
$testdata = array(
'Taxable returns:' => array(
'Individual income tax returns, total' => array(
'Returns with total positive income under $200,000 :' => array(
'Nonbusiness returns without Earned Income Tax Credit:' => array(
'Without Schedules C, E, F, or Form 2106' => array(79643929,262610,0.3,32922,229688),
'With Schedule E or Form 2106' => array(15997590,107300,0.7,49408,57892)
),
'Business returns without Earned Income Tax Credit:' => array(
'Nonfarm business returns by size of total gross receipts :' => array(
'Under $25,000' => array(10534942,94952,0.9,35192,59760),
'$25,000 under $100,000' => array(3124877,74825,2.4,24012,50813),
'$100,000 under $200,000' => array(877851,21724,2.5,13681,8043),
'$200,000 or more' => array(685163,13684,2.0,11549,2135)
),
'Farm returns' => array(1268251,4255,0.3,2475,1780)
),
'Business and nonbusiness returns with Earned Income' => array(
'Tax Credit by size of total gross receipts :' => array(
'Under $25,000' => array(6502703,459920,1.7,27009,432911),
'$25,000 or more' => array(1806228,18112,1.0,11161,6951)
)
)
),
'Returns with total positive income of at least $200,000 and under $1,000,000 :' => array(
'Nonbusiness returns' => array(4068298,71280,1.8,20795,50485),
'Business returns' => array(1734110,51151,2.9,17822,33329)
),
'Returns with total positive income of $1,000,000 or more' => array(416178,39753,9.6,13781,25972),
'International returns' => array(201097,8551,4.3,7269,1282),
)
));
function doit_recurse($cellname, $arr, $depth = 0) {
$ret = "";
if ($depth === 0) {
$ret .= "<table>";
}
$close_tr = "";
if (!empty($cellname)) {
$prefix = str_repeat (">", $depth);
$ret .= "<tr><td> $prefix $cellname</td>";
$close_tr = "</tr>";
}
foreach ($arr as $key => $value) {
if (is_numeric($value)) {
$ret .= "<td>$value</td>";
} else {
$ret .= $close_tr . doit_recurse($key, $value, $depth + 1);
}
}
if ($depth === 0) {
$ret .= "</tr></table>";
}
return $ret;
}
var_dump(doit_recurse('', $testdata));
here is the old and new output
old
string(2222) "<table><tr><td> > Taxable returns:</td></tr><tr><td> >> Individual income tax returns, total</td></tr><tr><td> >>> Returns with total positive income under $200,000 :</td></tr><tr><td> >>>> Nonbusiness returns without Earned Income Tax Credit:</td></tr><tr><td> >>>>> Without Schedules C, E, F, or Form 2106</td><td>79643929</td><td>262610</td><td>0.3</td><td>32922</td><td>229688</td></tr><tr><td> >>>>> Without Schedules C, E, F, or Form 2106</td><td>15997590</td><td>107300</td><td>0.7</td><td>49408</td><td>57892</td></tr><tr><td> >>>> Nonbusiness returns without Earned Income Tax Credit:</td></tr><tr><td> >>>>> Nonfarm business returns by size of total gross receipts :</td></tr><tr><td> >>>>>> Under $25,000</td><td>10534942</td><td>94952</td><td>0.9</td><td>35192</td><td>59760</td></tr><tr><td> >>>>>> Under $25,000</td><td>3124877</td><td>74825</td><td>2.4</td><td>24012</td><td>50813</td></tr><tr><td> >>>>>> Under $25,000</td><td>877851</td><td>21724</td><td>2.5</td><td>13681</td><td>8043</td></tr><tr><td> >>>>>> Under $25,000</td><td>685163</td><td>13684</td><td>2</td><td>11549</td><td>2135</td></tr><tr><td> >>>>> Nonfarm business returns by size of total gross receipts :</td><td>1268251</td><td>4255</td><td>0.3</td><td>2475</td><td>1780</td></tr><tr><td> >>>> Nonbusiness returns without Earned Income Tax Credit:</td></tr><tr><td> >>>>> Tax Credit by size of total gross receipts :</td></tr><tr><td> >>>>>> Under $25,000</td><td>6502703</td><td>459920</td><td>1.7</td><td>27009</td><td>432911</td></tr><tr><td> >>>>>> Under $25,000</td><td>1806228</td><td>18112</td><td>1</td><td>11161</td><td>6951</td></tr><tr><td> >>> Returns with total positive income under $200,000 :</td></tr><tr><td> >>>> Nonbusiness returns</td><td>4068298</td><td>71280</td><td>1.8</td><td>20795</td><td>50485</td></tr><tr><td> >>>> Nonbusiness returns</td><td>1734110</td><td>51151</td><td>2.9</td><td>17822</td><td>33329</td></tr><tr><td> >>> Returns with total positive income under $200,000 :</td><td>416178</td><td>39753</td><td>9.6</td><td>13781</td><td>25972</td></tr><tr><td> >>> Returns with total positive income under $200,000 :</td><td>201097</td><td>8551</td><td>4.3</td><td>7269</td><td>1282</td></tr></table>"
new
string(2178) "<table><tr><td> > Taxable returns:</td></tr><tr><td> >> Individual income tax returns, total</td></tr><tr><td> >>> Returns with total positive income under $200,000 :</td></tr><tr><td> >>>> Nonbusiness returns without Earned Income Tax Credit:</td></tr><tr><td> >>>>> Without Schedules C, E, F, or Form 2106</td><td>79643929</td><td>262610</td><td>0.3</td><td>32922</td><td>229688</td></tr><tr><td> >>>>> With Schedule E or Form 2106</td><td>15997590</td><td>107300</td><td>0.7</td><td>49408</td><td>57892</td></tr><tr><td> >>>> Business returns without Earned Income Tax Credit:</td></tr><tr><td> >>>>> Nonfarm business returns by size of total gross receipts :</td></tr><tr><td> >>>>>> Under $25,000</td><td>10534942</td><td>94952</td><td>0.9</td><td>35192</td><td>59760</td></tr><tr><td> >>>>>> $25,000 under $100,000</td><td>3124877</td><td>74825</td><td>2.4</td><td>24012</td><td>50813</td></tr><tr><td> >>>>>> $100,000 under $200,000</td><td>877851</td><td>21724</td><td>2.5</td><td>13681</td><td>8043</td></tr><tr><td> >>>>>> $200,000 or more</td><td>685163</td><td>13684</td><td>2</td><td>11549</td><td>2135</td></tr><tr><td> >>>>> Farm returns</td><td>1268251</td><td>4255</td><td>0.3</td><td>2475</td><td>1780</td></tr><tr><td> >>>> Business and nonbusiness returns with Earned Income</td></tr><tr><td> >>>>> Tax Credit by size of total gross receipts :</td></tr><tr><td> >>>>>> Under $25,000</td><td>6502703</td><td>459920</td><td>1.7</td><td>27009</td><td>432911</td></tr><tr><td> >>>>>> $25,000 or more</td><td>1806228</td><td>18112</td><td>1</td><td>11161</td><td>6951</td></tr><tr><td> >>> Returns with total positive income of at least $200,000 and under $1,000,000 :</td></tr><tr><td> >>>> Nonbusiness returns</td><td>4068298</td><td>71280</td><td>1.8</td><td>20795</td><td>50485</td></tr><tr><td> >>>> Business returns</td><td>1734110</td><td>51151</td><td>2.9</td><td>17822</td><td>33329</td></tr><tr><td> >>> Returns with total positive income of $1,000,000 or more</td><td>416178</td><td>39753</td><td>9.6</td><td>13781</td><td>25972</td></tr><tr><td> >>> International returns</td><td>201097</td><td>8551</td><td>4.3</td><td>7269</td><td>1282</td></tr></table>"
if you want the same result as in your example, use
function doit_recurse($cellname, $arr, $depth = 0) {
$ret = "";
if ($depth === 0) {
$ret .= "<table>";
}
$close_tr = "";
if (!empty($cellname)) {
$prefix = str_repeat (">", $depth);
$ret .= "<tr><td> $prefix $cellname</td>";
$close_tr = "</tr>";
}
foreach ($arr as $key => $value) {
if (is_numeric($value)) {
$ret .= "<td>$value</td>";
} else {
$ret .= $close_tr . doit_recurse(array_keys($arr)[0], $value, $depth + 1);
}
}
if ($depth === 0) {
$ret .= "</tr></table>";
}
return $ret;
}
Upvotes: 1