Nasıl birden fazla foreach döngüleri yerine bir döngü ya da bir özyinelemeli işlevi için '?'

5 Cevap php

I am stuck with a bunch of foreach loops and would like to know if there is a way to hone them down to a simple 'for' loop or a recursive function? I'm trying to generate HTML with the elements nested inside each other. I guess what I'm trying to get at is an arrays of arrays. But I don't know how to move forward with what I've created so far. Can someone please help me to make this monster into something more tamable? Thank you!

İşte benim kod:

$containers     = DISPLAY::displayParentElements($data);
$subcontainers  = DISPLAY::displayChildElements($data2);


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

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

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

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


Daha sonra sonuçlar aşağıdaki gibi görünecektir:

<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>


$containers dizisi şu bilgi vardır:

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
)


$subcontainers dizisi hemen hemen aynı bilgi, ancak ekstra bir anahtar ile vardır:

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
)

Ben iki diziler birine ya da sadece $containers dizi kullanarak daralmış olabilir eminim.

5 Cevap

Ben oldukça yazınızın söyleyemem, ama deftere kod var kodu, ve deftere çıktı istediğiniz çıktı alınır? Deftere ... Ben olmaz demek istiyorum, ama gerçekte ben emin olmak için yeterince iyi php bilmiyorum kodu ... deftere çıktı üretmek olmamalıdır. O hiç bir çıktıyı üretilen Aslında, ben şok olur. Dizi en deftere anahtar-değer çiftleri vardır. Tuşların hiçbiri 'parentDiv', 'childDiv', 'grandChildDiv' veya 'greatGrandChildDiv' gibi bir şey. Bunun yerine ilki için ve ikinci bir 'attribute_value' ve ikinci biri için 'parent_container_name' sadece 'attribute_value' vardır.

İstediğiniz çıktıyı üretmek için, bu satırlar boyunca bir şey deneyin:

$containerWasGenerated = new array();

echo '<div id="siteContainer">';
$containerWasGenerated['siteContainer'] = true;
foreach($containers as $container) {
    if($containerWasGenerated[$container['attribute_value'] != true) {
    	generateSubcontainers($container, $containers, $subcontainers, $containerWasGenerated);
    	$containerWasGenerated[$container['attribute_value']] = true;
    }
}
echo '</div>';

function generateSubcontainers($parent, $containers, $subcontainers, $containerWasGenerated) {
    echo '<div id="'.$parent['attribute_value'].'">';
    foreach($containers as $subcontainer) {
    	if(getParent($subcontainer, $subcontainers) == $parent['attribute_value']) {
    		generateContainer($subcontainer, $containers, $subcontainers, $containerWasGenerated);
    		$containerWasGenerated[$subcontainer['attribute_value']] = true;
    	}
    }
    echo '</div>';
}

function getParent($container, $subcontainers) {
    foreach($subconainters as $subcontainer) {
    	if($subcontainer['attribute_value'] == $container['attribute_value']) {
    		return $subcontainer['parent_container_name'];
    	}
    }
}

Yasal Uyarı: Bu kod denenmemiş ve benim php biraz paslı olduğunu, bu yüzden tüm halt gibi adamcağız olabilir. Ama bu doğru yönde olmalıdır. Ayrıca, yine de oldukça verimsiz. Parent_container_name tarafından sipariş Ekle alt dizi tutmak ve daha iyi bir getParent (örneğin bir ikili arama kullanarak) () fonksiyonu yazmak: hızlandırmak için tek yoldur. Umarım bu yardımcı olur.

Bu yalnızca alt kapsayıcınız ve mutlak üst kapsayıcı adını kullanır.

function printChildren($parent, $children) {
    echo '<div id="'.$parent.'">'."\n";
        foreach($children as $child) {
            if($child[0] == $parent) {
                printChildren($child[1], $children);
            }
    }
    echo '</div>'."\n";
}

printChildren('siteContainer', $subcontainers);

Not: Bu dışarı güzel değil sekmesi kodu yapar ...

You should give the nodes in $container a parent_container_name with a null value. This will represent the top-level menu nodes.

Sonraki, array_merge ile birlikte iki dizi tutkal.

Şimdi ortak boğum yapısı ile bir dizi var ki, kolayca geçerli düğümü eşleşen ve özyinelemeli yinelenen bir parent_container_name var alt öğeleri render, aşağı recurse olabilir.

Ben böyle bir şey istiyorum düşünüyorum:

$menuNodes; // The array of all nodes


function RenderMenu()
{
    // Grab all top-level nodes (nodes with no parent_container_name attribute)
    $topLevelNodes = array();

    foreach ($menuNodes as $node)
    	if ($node["parent_container_name"] == null)
    		$topLevelNodes[] = $node;


    foreach ($topLevelNodes as $node)
    	RenderMenuNode($node);
}

function RenderMenuNode($node)
{
    print "<div id='" . $node["attribute_value"] ."'>";
    $node["isRendered"] = true;

    // This filtering callback will discard elements that are not children or have already been rendered.
    function Filter($element)
    {
    	global $node;
    	return (!$element["isRendered"] && $element["parent_container_name"] == $node["parent_container_name]"]);
    }

    $children = array_filter($menuNodes, 'Filter');

    foreach ($children as $child)
    	RenderMenuNode($child);

    print "</div>";
}

Ben çalıştırmak veya bu kodu test, ve kesinlikle daha verimli olabilir, ama umarım bu doğru yönde işaret değil. Eğer gereksiz yere düğümleri üzerinde yeniden-yineleme değil böylece İdeal menuNodes diziden render düğümleri kaldıracaktır.

Bu şekilde ardışık menü yapısını tanımlayarak, menüler kodunu değiştirmek zorunda kalmadan derin istediğiniz gibi iç içe olabilir. Bu yardımcı olur umarım!

Bunu yapmanın en iyi yolu daha fazla veri gibi temsil etmek istediğiniz dizi yapmak olacaktır. Yani anahtar-değer çiftleri daha related olması gerekir. Ben şu diziyi yaratacak:

$new_array = array(
    [siteContainer] => array(
        [header] => array(
            [0] => "logo",
            [1] => "links",
            [contactInfo"] => array (
                [0] => "logoInfo",

            ....

           )
        )
     )
 );

Eğer yazardı özyinelemeli işlevi aşağıdakileri yapmak için:

function makeSubDiv($array)
{
    foreach($array as $key=>$value)
    {
         if(is_array($value))
         {
             echo '<div id="'.$key.'">';
                 makeSubDiv($value);
             echo '</div>';
         }
         else
         {
              echo '<div id="'.$value.'"></div>';
         }
    }
}

Son olarak şu anda ben gibi bir şey olurdu var diziyi birleştirmek için.

// not sure why you have $containers because the data seems to be in subcontainers
$containers     = DISPLAY::displayParentElements($data);
$subcontainers  = DISPLAY::displayChildElements($data2);

function mergeToNested($subcontainers)
{
    $return = array();
    foreach($containers as $values)
    {
        $key = $values["parent_container_name";
        if(isset($return[$key]))
        {
            if(is_array($return[$key]))
            {
                array_merge($return[$key], mergeToNested($return[$key]));
            }
            else
            {
                $return[$key] = array($values["attribute_value"]);
            }
        }
        else if($index = array_search($key, $return) !== false)
        {
             unset($return[$index]);
             $return[$key] = array();
        }
        else
        {
             $return[] = $key;
        }
     }

     return $return;
}

Ahh, Umarım $ kapları ve mergeToNested() fonksiyonu sayesinde onları itmek zorunda kalmadan iç içe $ alt kapsayıcınız alabilirsiniz.

Note:

Beklendiği gibi bu kod (especially the MergeToNested function) test değil, istediğiniz verileri almak için nasıl bir fikir, her iç içe seviyelere birleştirme değil. ... Herhangi değişiklikleri test ve düzenlemek için çekinmeyin.

Ben sadece o yerine düzenleme yeni biri yapmak için daha iyi olacağını düşündüm, benim cevap için pek çok değişiklik yaptı.

I halinde öyleydi am giriş diziyi dahil ediyorum bu sefer i ile başlayan ne yanlış. Ben de herhangi bir anne olmadan anne olan tüm mutlak anne, bulmak için bir fonksiyon yarattık.

// list of subcontainers and their parents
$subcontainers = array(
array('siteContainer', 'header'), array('header', 'logoContainer'),
array('header', 'logo'), array('contactInfo', 'logoText'),
array('header', 'links'), array('header', 'contactInfo'),
array('siteContainer', 'body'), array('body', 'longDiv'),
array('logoText', 'shortDiv'), array('shortDiv', 'headerText'),
array('body', 'greetings'));

// recursively prints each container
function printChildren($parent, $children) {
    echo '<div id="'.$parent.'">'."\n";
    foreach($children as $child) {
        if($child[0] == $parent) {
            printChildren($child[1], $children);
        }
    }
    echo '</div>'."\n";
}

// finds all parents that have no parents
function findAbsParent($subcontainers) {
    $absParents = array();
    foreach($subcontainers as $parent) {
        $isAbs = true;
        foreach($subcontainers as $child) {
            if($parent[0] == $child[1]) {
                $isAbs = false;
            }
        }
        if($isAbs) {$absParents[] = $parent[0];}
    }
    return array_unique($absParents);
}

$absparents = findAbsParent($subcontainers);
// this is only needed if it's possible to have more then one absolute parent
if(is_array($absparents)) {
    foreach($absparents as $absparent) {printChildren($absparent, $subcontainers);}
} else {
    printChildren($absparents, $subcontainers);
}