Jump to content

[SOLVED] One 'for' loop to simplify multiple nested foreach loops


Recommended Posts

Hello:

 

I have several nested foreach loops like so:

 

foreach($this1 as $that1) {
    //extract info, etc...

    foreach($this2 as $that2) {
        //extract info, etc...

        foreach($this3 as $that3) {
            //extract info, etc...

            foreach($this4 as $that4) {
                //extract info, etc...

                foreach($this5 as $that5) {
                    //extract info, etc...

                }
            }
        }
    }
}

 

This is a monster. Is there a way to write a 'for' loop that can iterate through as many nested foreach loops as needed? I don't mind creating a bunch of these foreach loops but somehow I feel that there is a better way. My main priority is to keep the nested order.

 

Thank you!

Can you show the array(s) your looping through, will be easier to understand

 

 

Good point! I'm actually pulling info from a database via two classes.

 

$containers = DISPLAY::displayParentElements($blah);
$subcontainers  = DISPLAY::displayChildElements($blah);

 

 

I then place the resultsets into foreach loops:

foreach($containers as $parent) {
    //extract info, etc...
    $parentDiv = $parent['parentDiv'];
     echo '<div id="'.$parentDiv.'">';

    foreach($subcontainers as $child) {
        //extract info, etc...
        $childDiv = $child['childDiv'];
        echo '<div id="'.$childDiv.'">';

        foreach($subcontainers as $grandChild) {
            //extract info, etc...
            $grandChildDiv = $grandChild['grandChildDiv'];
            echo '<div id="'.$grandChildDiv.'">';

            foreach($subcontainers as $greatGrandChild) {
                //extract info, etc...
                $greatGrandChildDiv = $greatGrandChild['greatGrandChildDiv'];
                echo '<div id="'.$greatGrandChildDiv.'">';
                echo '</div>';
            }

            echo '</div>';
        }
        echo '</div>';
    }
echo '</div>';
}

 

The results will look like this (ignore the attribute values as they are just test names):

<div id="siteContainer">
      <div id="header">
            <div id="logoContainer">/div>
            <div id="logo"></div>
            <div id="links"></div>
            <div id="contactInfo">
                  <div id="logoText">
                        <div id="shortDiv">
                              <div class="headerText"></div>
                        </div>
                  </div>
             </div>
      </div>
      <div id="body">
            <div id="longDiv"></div>
            <div id="greetings"></div>
      </div>
<div>

 

 

Basically, I take the resultset and create div tags for each record. The fun comes in iterating through each result and checking to see if it's a child of another element.  If it is then it is echo'd between the parents div tags. The multiple foreach loops do this for as many records that are returned until there are none left to check.

 

Would a recursive function work best in this situation? If so, any examples? I have not worked with recursives yet but have look at info online.

It sounds like the nested foreach's is what you need. Without seeing the working code it would be hard to find another solution, though if that's working fine I'm not sure that another solution is needed.

 

You could use a recursive function, but if I'm honest I'm not sure how to best write it for that amount of looping, especially without the actual code.

What is the out of

echo '<pre>' . print_r($containers , true) . '</pre>';
echo '<pre>' . print_r($subcontainers , true) . '</pre>';

 

Looking at your code you do not need 4 nested foreach loops at all. Only two should do it

It sounds like the nested foreach's is what you need. Without seeing the working code it would be hard to find another solution, though if that's working fine I'm not sure that another solution is needed.

 

You could use a recursive function, but if I'm honest I'm not sure how to best write it for that amount of looping, especially without the actual code.

 

 

I've provided the working code and the results

$containers is from a database query that returns the attribute values:

 

siteContainer
      header
            logoContainer
            logo
            links
            contactInfo
                  logoText
                        shortDiv
                              headerText
      body
            longDiv
            greetings

 

Bu you are right, the nested loops is working well. However, I wanted something more dynamic than having to manually create ten nested foreach loops.

What is the out of

echo '<pre>' . print_r($containers , true) . '</pre>';
echo '<pre>' . print_r($subcontainers , true) . '</pre>';

 

Looking at your code you do not need 4 nested foreach loops at all. Only two should do it

 

Two works fine. But if there are divs that are nested within other divs then I need to account for that. I guess I'm looking for a better way to code this. Here are the db array results:

 

The two arrays contain the same info except that $subcontainers has an extra column for listing which element is its parent element. Each array results is wrapped around div tags:

 

foreach($containers as $parent){
    echo '<div id="'.$parent['attribute_value'].'"></div>';
}

 

 

Array results:

echo '<pre>' . print_r($containers , true) . '</pre>'; ==>

Array
(
    [attribute_value] => siteContainer
)

Array
(
    [attribute_value] => header
)

Array
(
    [attribute_value] => logoContainer
)

Array
(
    [attribute_value] => logo
)

Array
(
    [attribute_value] => logoText
)

Array
(
    [attribute_value] => links
)

Array
(
    [attribute_value] => contactInfo
)

Array
(
    [attribute_value] => body
)

Array
(
    [attribute_value] => longDiv
)

Array
(
    [attribute_value] => shortDiv
)

Array
(
    [attribute_value] => headerText
)

Array
(
    [attribute_value] => greetings
)

 

 

echo '<pre>' . print_r($subcontainers , true) . '</pre>'; ==>

Array
(
    [parent_container_name] => siteContainer
    [attribute_value] => header
)

Array
(
    [parent_container_name] => header
    [attribute_value] => logoContainer
)

Array
(
    [parent_container_name] => header
    [attribute_value] => logo
)

Array
(
    [parent_container_name] => contactInfo
    [attribute_value] => logoText
)

Array
(
    [parent_container_name] => header
    [attribute_value] => links
)

Array
(
    [parent_container_name] => header
    [attribute_value] => contactInfo
)

Array
(
    [parent_container_name] => siteContainer
    [attribute_value] => body
)

Array
(
    [parent_container_name] => body
    [attribute_value] => longDiv
)

Array
(
    [parent_container_name] => logoText
    [attribute_value] => shortDiv
)

Array
(
    [parent_container_name] => shortDiv
    [attribute_value] => headerText
)

Array
(
    [parent_container_name] => body
    [attribute_value] => greetings
)

try

<?php
$subcontainers =array( Array
(
    'parent_container_name' => 'siteContainer',
    'attribute_value' => 'header'
),

Array
(
    'parent_container_name' => 'header',
    'attribute_value' => 'logoContainer'
),

Array
(
    'parent_container_name' => 'header',
    'attribute_value' => 'logo'
),

Array
(
    'parent_container_name' => 'contactInfo',
    'attribute_value' => 'logoText'
),

Array
(
    'parent_container_name' => 'header',
    'attribute_value' => 'links'
)
,
Array
(
    'parent_container_name' => 'header',
    'attribute_value' => 'contactInfo'
)
,
Array
(
    'parent_container_name' => 'siteContainer',
    'attribute_value' => 'body'
)
,
Array
(
    'parent_container_name' => 'body',
    'attribute_value' => 'longDiv'
)
,
Array
(
    'parent_container_name' => 'logoText',
    'attribute_value' => 'shortDiv'
)
,
Array
(
    'parent_container_name' => 'shortDiv',
    'attribute_value' => 'headerText'
)
,
Array
(
    'parent_container_name' => 'body',
    'attribute_value' => 'greetings'
)
);
foreach ($subcontainers as $item) $my_arr[$item['parent_container_name']][] = $item['attribute_value'];
//print_r($my_arr);

function my_div($array, $start,$ident=0){
echo str_repeat("\t",$ident),"<div id=\"$start\">";
if (isset($array[$start])) {
	echo "\n";
	foreach ($array[$start] as $i)my_div($array,$i,$ident+1);
}
if (isset($array[$start])) echo str_repeat("\t",$ident);
echo "</div>\n";
}
my_div($my_arr,'siteContainer');
?>

Sasa...you are awesome!!! This works as I had hoped it would. Thank you. I'm perplexed at how simple it looks yet it is so powerful! I owe you a latte my friend! ;)

 

How would I allow other database column info to trickle in there? For example, I have another column entitled 'attribute_name'.

 

Would I append to the following?

$my_arr[$item['parent_container_name']][] = $item['attribute_value'].$item['attribute_name'];

 

Probably not but I've tried different configurations and I can't get other columns to spit out appropriately.

 

Again, thank you for your help...much appreciated!!!

try

foreach ($subcontainers as $item) $my_arr[$item['parent_container_name']][] = $item;
// add all $item to my_array
//print_r($my_arr);

function my_div($array, $start,$ident=0){
echo str_repeat("\t",$ident),"<div id=\"$start\">";
if (isset($array[$start])) {
	echo "\n";
	foreach ($array[$start] as $i)my_div($array,$i['attribute_value'],$ident+1);//add what part of $i (item) i want
}
if (isset($array[$start])) echo str_repeat("\t",$ident);
echo "</div>\n";
}
my_div($my_arr,'siteContainer');

Sasa:

 

To add other db column info I would need to write the code like so:

function my_div($array,$start,$atrName,$ident=0){
     echo str_repeat("    ",$ident),'div '.$atrName.'="'.$start.'">';
     if (isset($array[$start])) {
          echo "<br />";
       foreach ($array[$start] as $i)
	    my_div($array,$i['attribute_value'],$i['attribute_name'],$ident+1); //add what part of $i (item) i want
}
if (isset($array[$start]))
echo str_repeat("    ",$ident);
echo "/div> !-- end.$start --><br />";
}
my_div($my_arr,'siteContainer','id');

 

However, I don't like that I have to hardcode the values, 'siteContainer','id', to get this to work:

my_div($my_arr,'siteContainer','id');

 

Is there are workaround for that? I would like for it all to be dynamic.

 

 

This thread is more than a year old. Please don't revive it unless you have something important to add.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.