2009-08-18 8 views
1

私はforeachループの束に悩まされており、単純なforループまたは再帰関数にそれらを磨く方法があるかどうかを知りたいですか?私は相互に入れ子になった要素でHTMLを生成しようとしています。私が得ようとしているのは、配列の配列です。しかし、私はこれまでに作ったものをどのように前進させるのか分かりません。 誰かがこのモンスターをもっと覚えやすいものにする手伝ってもらえますか?ありがとうございました!複数のforeachループを 'for'ループまたは再帰関数に置き換えるにはどうすればよいですか?

ここに私のコードです:

$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>'; 
} 

結果はこのようになります。

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 
) 

<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配列は、以下の情報を持っています


$subcontainers配列はほとんど同じ情報を持っていますが、余分なキーを使用して:

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 
) 

私は、2つの配列が一つにのみ$containers配列を使用して絞り込むことができかなり確信しています。

答えて

1

あなたの投稿からはかなり分かりませんが、あなたが投稿したコードはあなたのコードであり、投稿した出力はあなたが望む出力ですか?あなたが投稿したコード...私は言うつもりはありませんが、実際には私はphpをよく知っていません。あなたが投稿した出力を生成すべきではありません。実際には、それが何らかのアウトプットを生み出すのであれば、私はショックを受けるだろう。投稿した配列にはキーと値のペアがあります。どのキーも 'parentDiv'、 'childDiv'、 'grandChildDiv'、 'greatGrandChildDiv'のようなものではありません。代わりに、最初のものは 'attribute_value'、2番目のものは 'attribute_value'と 'parent_container_name'です。

したい出力を生成するために、これらの線に沿って何かを試してみてください。

$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']; 
     } 
    } 
} 

免責事項:このコードはテストされていないと、それはすべて一体としてバグがありので、私のPHPは、少しさびています。しかし、それは正しい方向にあるべきです。また、それはまだかなり非効率的です。それをスピードアップする方法の1つは、サブコンテナの配列をparent_container_nameの順に並べ、より良いgetParent()関数を書くことです(インスタンスのバイナリ検索を使用)。うまくいけば、これは役に立ちます。

0

これは、サブコンテナと絶対親コンテナの名前のみを使用します。

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

注:これがうまく出てタブコードはない...

+0

このコードは素晴らしいですが、期待どおりに動作しませんでした。しかし、なぜ値(例: 'siteContainer')を次の行にハードコードする必要があるのか​​不思議です: printChildren( 'siteContainer'、$ subcontainers); –

+0

絶対的な親(例えば 'siteContainer')を見つける方法を含む、より多くの情報で新しい回答を作成しました。また、$ subcontainersをどのように定義したかも記載しました。そのコードが期待どおりに動作していないかの答え – Samuel

0

あなたは、null値を$コンテナ内のノードにparent_container_nameを与える必要があります。この はトップレベルのメニューノードを表します。

次に、array_mergeを使用して2つのアレイを接着します。の子孫要素をレンダリングして、再帰的に繰り返すことができます。parent_container_nameの子要素をレンダリングして再帰的に繰り返します。

は、私はあなたがこのような何かしたいと思う:私は実行またはこのコードをテストしていない

$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>"; 
} 

を、そして、それは間違いなく、より効率的かもしれないが、うまくいけば、それは正しい方向にあなたを指しています。理想的には、レンダリングされたノードをmenuNodes配列から削除して、ノードを不必要に反復処理しないようにします。

このようにメニュー構造を再帰的に定義することで、コードを変更することなく、好きなだけ深くネストされたメニューを作成できます。お役に立てれば!

0

これを行う最善の方法は、配列を表現したいデータのようにすることです。したがって、キーと値のペアはとなります。です。最後に、あなたは現在、私のようなものを持っているでしょう持つ配列をマージする

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>'; 
     } 
    } 
} 

:あなたが書くでしょう再帰関数で、次の操作を行うに

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

      .... 

      ) 
     ) 
    ) 
); 

:私は、次の配列を作成します。

// 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; 
} 

なんてこった、うまくいけば、あなたは$コンテナとmergeToNested()機能を介してそれらをプッシュすることなく、ネストされた$サブコンテナを得ることができます。

このコード(特にMergeToNested機能)がテストされていない、それは予想通り、それはすべてのネストされたレベルにマージしないことがあり、必要なデータを取得する方法のアイデアです。 ...すべての変更をテストして編集してください。

+0

このコードは、私にとって扱いにくいものになりました。 –

0

私は自分の答えに多くの変更を加えました。私は編集の代わりに新しいものにするほうがよいと思いました。

今回は入力配列を含めていますが、私はあなたの出発点を誤解した場合に使用しています。私はまた、すべての絶対的な親を見つける機能を作りました。つまり、両親のない親です。

// 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); 
} 
関連する問題